转换包含到表达式树

相关: 创建具有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); } }