将List.Contains转换为表达式树
相关:
使用3个条件创建Lambda表达式
转换包含到表达式树
在我上一个问题的下面,我遇到了这个查询,我想编写Expression Tree
版本:
List lst = new List{1,2}; from a in myTbl where a.Age = 20 && lst.Contains(a.Status) select a
我写这段代码:
List lst = new List{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>(body, param); return lambda;
我收到错误:
“类型’System.Nullable`1 [System.Byte]’上没有方法’包含’。”
请帮我找到问题所在。
谢谢
问题是你已经将两个参数切换到Expression.Call
,你的代码试图创建无意义的表达式o.Status.Contains(lst)
。
你需要切换两个参数:
Expression.Call(Expression.Constant(lst), "Contains", Type.EmptyTypes, Expression.PropertyOrField(param, "Status"))
这假设你正在使用的LINQ提供程序理解List
。 如果你需要Enumerable.Contains()
,那么看看Ivan Stoev的答案。
转换包含到表达式树的区别在于我们在那里调用了一个string
实例 Contains
方法,而在这里我们需要调用一个静态generics方法Enumerable.Contains
:
public static bool Contains( this IEnumerable source, TSource value )
它可以通过使用另一个Expression.Call overload
来实现:
public static MethodCallExpression Call( Type type, string methodName, Type[] typeArguments, params Expression[] arguments )
像这样:
// Enumerable.Contains(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) );