开发者

Building a lambda WHERE expression to pass into a method

I need to pass in a "where" lambda expression that'll be used in a LINQ query inside a method. The problem is, I don't know what the where value will be compared against until I get into the method.

Now to explain further and clarify some of what I said above I'll come up with a bit of a contrived example.

Imagine I have a List<Products> and I need to narrow that list down to a single record using a productId property of the Products object. Normally I would do this:

var product = productList.Where(p=>开发者_StackOverflow中文版p.productId == 123).FirstOrDefault();

Now take it a step further - I need to put the above logic into a method that isn't limited to a List<Products> but is instead a List<T> so ideally, I'd be calling it like this (and I know the below won't work, it's simply here to show what I am trying to achieve):

myMethod(productList, p => p.productId == X)

With the caveat being that X isn't known until I'm inside the method.

Finally, for what it's worth, I need to point out that my collection of data is an OData DataServiceQuery.

So, to re-summarize my question: I need to know how to construct a lambda "where" expression that I can pass into a method and how to use it against a collection of objects in a LINQ query.


myMethod(productList, p => p.productId == X) - you can emulate with this trick

    static void myMethod<T>(List<T> list, Func<T,bool> predicate, ref int x)
    {
        x = 5;
        var v = list.Where(predicate);
        foreach (var i in v)
            Console.Write(i);
        Console.ReadLine();
    }

    static void Main(string[] args)
    {
        List<int> x = new List<int> { 1, 2, 3, 4, 5 };
        int z = 0;
        myMethod(x, p => p == z, ref z);
    }

but not sure if it solves your problem in whole


For one, if you are going to query an IEnumerable<T>, you will need to ensure that your comparison will work in the first place. In that case you can make your objects implement an interface that guarantees that they will support the comparison.

Once you do that, your method can have a generic constraint that limits the input to those interfaces. At that point, your method can take a Func, which can be passed to the LINQ Where clause:

public interface Identifier
{
   int Id { get; set; }
}

public class Product : Identifier
{
   public int Id { get; set; }
   //Other stuff
}

public T GetMatch<T>(IEnumerable<T> collection, Func<T, int, bool> predicate) where T : Identifier
{
   int comparison = 5;
   return collection.Where(item => predicate(item, comparison)).FirstOrDefault();
}

Which can be invoked like:

var match = GetMatch<Identifier>(collection, (x, y) => x.Id == y);

UPDATE: I modified the above code to take in a comparison parameter


You could try to use the PredicateBuilder class from the free LinqKit library(tutorial).

You can then construct a predicate using

PredicateBuilder predicate = PredicateBuilder.True<T>();
predicate = PredicateBuilder.And(predicate, p=> p.product_id == X);

where X is of type T.

You can use this predicate in a where clause such as .Where(predicate) and return an IQueryable or return the predicate itself which would be of type Expression<Func<T, bool>>

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜