【问题标题】:Building a lambda WHERE expression to pass into a method构建 lambda WHERE 表达式以传递给方法
【发布时间】:2011-08-12 21:12:19
【问题描述】:

我需要传入一个“where”lambda 表达式,该表达式将在方法内的 LINQ 查询中使用。问题是,在我进入该方法之前,我不知道将与 where 值进行比较。

现在为了进一步解释和澄清我上面所说的一些内容,我将提出一个人为的例子。

假设我有一个 List<Products>,我需要使用 Products 对象的 productId 属性将该列表缩小到一条记录。通常我会这样做:

var product = productList.Where(p=>p.productId == 123).FirstOrDefault();

现在更进一步——我需要将上述逻辑放入一个不限于List<Products> 而是List<T> 的方法中,所以理想情况下,我会这样称呼它(并且我知道下面的行不通,它只是在这里展示我想要实现的目标):

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

需要注意的是,X 在我进入方法之前是未知的。

最后,就其价值而言,我需要指出我的数据集合是 OData DataServiceQuery

所以,重新总结一下我的问题:我需要知道如何构造一个可以传递给方法的 lambda“where”表达式,以及如何将它用于 LINQ 查询中的对象集合。

【问题讨论】:

  • T 总是有 productId 属性?
  • 不,productId 并不总是属性。有时我可能有一个用户列表,所以它可能是 UserId,或者可能是一组 Company 对象的 companyId。

标签: linq c#-4.0 lambda odata


【解决方案1】:

myMethod(productList, p => p.productId == X) - 你可以用这个技巧来模拟

    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);
    }

但不确定它是否能完全解决您的问题

【讨论】:

  • 有趣的想法!如果你在某处看到这个实现,你会认为它是 hack 吗?
  • 没看到实现,但不是hack,从语法角度来看是合法的
【解决方案2】:

首先,如果您要查询IEnumerable&lt;T&gt;,您首先需要确保您的比较有效。在这种情况下,您可以让您的对象实现一个接口,以保证它们支持比较。

一旦你这样做了,你的方法就可以有一个通用的约束来限制这些接口的输入。此时,您的方法可以采用 Func,可以将其传递给 LINQ Where 子句:

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();
}

可以这样调用:

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

更新: 我修改了上面的代码以接受比较参数

【讨论】:

  • 感谢 Dave - 主要问题是在执行该方法之前我不知道 5 的值。
  • @Chu -- 是值(在提供的示例中为 5),将作为参数传递给 GetSubcollection 方法吗?值如何进入函数范围?
  • @Chu -- 我在上面添加了一个参数来显示如何将比较值添加到 Func
  • GetSubCollection 方法实际上决定了在比较中使用的值。
  • @Chu -- 在上次编辑中,我在 GetMatch 方法的主体中包含了任意比较...这样,该方法确定了比较值,但调用该方法决定了如何进行比较。
【解决方案3】:

您可以尝试使用免费 LinqKit 库 (tutorial) 中的 PredicateBuilder 类。

然后您可以使用构造谓词

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

其中 X 属于 T 类型。

您可以在 .Where(predicate) 等 where 子句中使用此谓词并返回 IQueryable 或返回类型为 Expression&lt;Func&lt;T, bool&gt;&gt; 的谓词本身

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多