转换包含到表达式树
相关: 创建具有3个条件的Lambda表达式
请考虑以下代码:
from a in myTbl where a.Address.Contains(strToCheck) select a
我如何将其转换为表达式树并使用表达式编写上面的代码? 主要问题是将a.Address.Contains(strToCheck)
转换为Expression Tree
。
编辑1)地址是一个string
字段, strToCheck
是一个string
谢谢
a.Address.Contains(strToCheck)
表示对具有strToCheck
参数的 string.Contains
实例上的a.Address
实例 方法的 调用 。
构建相应表达式的最简单方法是使用以下Expression.Call
重载 :
public static MethodCallExpression Call( Expression instance, string methodName, Type[] typeArguments, params Expression[] arguments )
像这样(使用链接问题中的术语):
var body = Expression.Call( Expression.PropertyOrField(param, "Address"), // instance "Contains", // method Type.EmptyTypes, // no generic type arguments Expression.Constant(strToCheck) // argument );
你没有指定myTbl的类型,
所以我使用一个对象列表创建了一个简单的解决方案。
using System; using System.Linq; using System.Linq.Expressions; using System.Collections.Generic; namespace Test { class Program { static void Main(string[] args) { var adresses = FilterByAddress("Address", new List { new Person { Address = "Address1" }, new Person { Address = "AAAAAA" } }); } public static IEnumerable FilterByAddress(string strToCheck, List list) { var listParam = Expression.Parameter(typeof(IEnumerable ), "list"); Expression> contains = a => a.Address.Contains(strToCheck); var select = typeof(Enumerable).GetMethods().Single(m => m.Name.Equals("Where") && m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2); var genericMethod = select.MakeGenericMethod(new[] { typeof(Person) }); var call = Expression.Call(null, genericMethod, new Expression[] { listParam, contains }); var lambda = Expression.Lambda, IEnumerable >>(call, new[] { listParam }); return lambda.Compile().Invoke(list); } } public class Person { public string Address { get; set; } } }
如果要使用谓词filter,可以将Expresssion
作为参数传递(一行)
static void Main(string[] args) { var strToCheck = "Address"; var list = new List { new Person { Address = "Address1" }, new Person { Address = "AAAAAA" } }; var adresses = FilterByAddress(list, p => p.Address.Contains(strToCheck)); } public static IEnumerable FilterByAddress(List list, Expression> predicateEx) { var listParam = Expression.Parameter(typeof(IEnumerable ), "list"); var select = typeof(Enumerable).GetMethods().Single(m => m.Name.Equals("Where") && m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2); var genericMethod = select.MakeGenericMethod(new[] { typeof(Person) }); var call = Expression.Call(null, genericMethod, new Expression[] { listParam, predicateEx }); var lambda = Expression.Lambda, IEnumerable >>(call, new[] { listParam }); return lambda.Compile().Invoke(list); }
如果你有一个跨越多行的非常复杂的谓词(表达式树可以从一行lambda中计算),你可以使用一个技巧从谓词Func构造一个表达式树,如下所示:
static void Main(string[] args) { var strToCheck = "Address"; Func predicate = p => { return p.Address.Contains(strToCheck); }; var list = new List { new Person { Address = "Address1" }, new Person { Address = "AAAAAA" } }; var adresses = FilterByAddress(list, predicate); } public static IEnumerable FilterByAddress(List list, Func predicate) { var listParam = Expression.Parameter(typeof(IEnumerable ), "list"); Expression> predicateEx = p => predicate(p); var select = typeof(Enumerable).GetMethods().Single(m => m.Name.Equals("Where") && m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2); var genericMethod = select.MakeGenericMethod(new[] { typeof(Person) }); var call = Expression.Call(null, genericMethod, new Expression[] { listParam, predicateEx }); var lambda = Expression.Lambda, IEnumerable >>(call, new[] { listParam }); return lambda.Compile().Invoke(list); }
使用通用方法按谓词过滤列表
static void Main(string[] args) { var strToCheck = "Address"; Func predicate = p => { return p.Address.Contains(strToCheck); }; var list = new List { new Person { Address = "Address1" }, new Person { Address = "AAAAAA" } }; var adresses = FilterBy (list, predicate); } public static IEnumerable FilterBy (List list, Func predicate) { var listParam = Expression.Parameter(typeof(IEnumerable ), "list"); Expression> predicateEx = p => predicate(p); var select = typeof(Enumerable).GetMethods().Single(m => m.Name.Equals("Where") && m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2); var genericMethod = select.MakeGenericMethod(new[] { typeof(T) }); var call = Expression.Call(null, genericMethod, new Expression[] { listParam, predicateEx }); var lambda = Expression.Lambda, IEnumerable >>(call, new[] { listParam }); return lambda.Compile().Invoke(list); } }