tags:

views:

37

answers:

3

I'm trying to write a set of filtering functions that can be chained together to progressively filter a data set. What's tricky about this is that I want to be able to define the filters in a different context from that in which they'll be used. I've gotten as far as being able to pass a very basic function to the Where() clause in a LINQ statement:

filters file:

Func<item, bool> returnTrue = (i) => true;

repository file:

public IQueryable<item> getItems()
{
    return DataContext.Items.Where(returnTrue);
}

This works. However, as soon as I try to use more complicated logic, the trouble begins:

filters file:

Func<item, bool> isAssignedToUser = (i) => i.assignedUserId == userId;

repository file:

public IQueryable<item> getItemsAssignedToUser(int userId)
{
    return DataContext.Items.Where(isAssignedToUser);
}

This won't even build because userId isn't in the same scope as isAssignedToUser(). I've also tried declaring a function that takes the userId as a parameter:

Func<item, int, bool> isAssignedToUser = (i, userId) => i.assignedUserId == userId;

The problem with this is that it doesn't fit the function signature that Where() is expecting:

Func<item, bool>

There must be a way to do this, but I'm at a loss for how. I don't feel like I'm explaining this very well, but hopefully you get the gist.

Thanks,

Daniel

A: 

Thanks to the wonders of closures the userId is already in the scope if you use an inline anonymous function in your Where clause. This means that when you have an anonymous function in a method, variables within the method are available to the anonymous function even though they seem to be "outside."

public IQueryable<item> getItemsAssignedToUser(int userId)
{
    return DataContext.Items.Where( i => i.assignedUserId == userId);
}

You also could have created the Func isAssignedToUser inside the method getItemsAssignedToUser and passed it to the Where clause like this, but it would be unnecessary:

public IQueryable<item> getItemsAssignedToUser(int userId)
{
    Func<item, bool> isAssignedToUser = (i) => 
    {
        return i.assignedUserId == userId; 
    };

    return DataContext.Items.Where(isAssignedToUser);
}
Corey Sunwold
A: 

You don't need to declare your functions as pure standalone functions. You can use an inline lambda:

public IQueryable<item> getItemsAssignedToUser(int userId)
{
    return DataContext.Items.Where(i => i.assignedUserId == userId);
}

The official documentation for lambdas is here on MSDN, but you might find easier-to-read results searching on Google.

Mark Rushakoff
A: 

I answered a similar question here on SO yesterday. It describes an alternative way of filtering by passing in 'filter object' that allow you to transform one IQueryable to another. Take a look.

Steven