【问题标题】:Convert List.Contains to Expression Tree将 List.Contains 转换为表达式树
【发布时间】:2017-10-07 13:10:40
【问题描述】:

相关:

Create a Lambda Expression With 3 conditions

Convert Contains To Expression Tree

在我之前的问题中,我遇到了这个我想写Expression Tree版本的查询:

List<byte?> lst = new List<byte?>{1,2};
from a in myTbl
where a.Age = 20 && lst.Contains(a.Status)
select a

我写了这段代码:

List<byte?> lst = new List<byte?>{1,2};
var param = Expression.Parameter(typeof(T), "o");
var body = Expression.AndAlso(
               Expression.Equal(
                    Expression.PropertyOrField(param, "Age"),
                    Expression.Constant(20)
               ),
               Expression.Call(Expression.PropertyOrField(param, "Status"),
                                   "Contains",
                                   Type.EmptyTypes, 
                                   Expression.Constant(lst)));

var lambda = Expression.Lambda<Func<T, bool>>(body, param);
return lambda;

我得到了错误:

“'System.Nullable`1[System.Byte]' 类型上不存在方法 'Contains'。”

请帮我找出问题。

谢谢

【问题讨论】:

    标签: c# linq lambda expression-trees


    【解决方案1】:

    Convert Contains To Expression Tree 的不同之处在于我们调用了string instance Contains 方法,而这里我们需要调用静态 泛型方法@ 987654322@:

    public static bool Contains<TSource>(
        this IEnumerable<TSource> source,
        TSource value
    )
    

    可以通过使用另一个Expression.Call overload来实现:

    public static MethodCallExpression Call(
        Type type,
        string methodName,
        Type[] typeArguments,
        params Expression[] arguments
    )
    

    像这样:

    // Enumerable.Contains<byte?>(lst, a.Status)
    var containsCall = Expression.Call(
        typeof(Enumerable), // type
        "Contains", // method
        new Type[] { typeof(byte?) }, // generic type arguments (TSource)
        Expression.Constant(lst),  // arguments (source)
        Expression.PropertyOrField(param, "Status")  // arguments (value)
    );
    

    【讨论】:

      【解决方案2】:

      问题是您已将两个参数切换为Expression.Call,您的代码正试图创建无意义的表达式o.Status.Contains(lst)

      你需要切换两个参数:

      Expression.Call(Expression.Constant(lst),
          "Contains",
          Type.EmptyTypes, 
          Expression.PropertyOrField(param, "Status"))
      

      这是假设您使用的 LINQ 提供程序理解 List&lt;T&gt;.Contains()。如果您需要Enumerable.Contains(),请查看 Ivan Stoev 的回答。

      【讨论】:

        猜你喜欢
        • 2012-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-08
        • 2018-03-05
        • 1970-01-01
        • 2011-04-09
        相关资源
        最近更新 更多