2017-05-14 101 views
2

如何转换这lambda来表达树在C#创建动态表达式树

var FieldName="SomeDynamicField"; 
var param = "SomeParam" 
//Lambda to beCreated 
x=>x.FieldName!=null && x.FieldName.ToLower().Contains(param) 

我已经试过这到目前为止

private static Expression GetPropertyExpression(PropertyInfo prop, ParameterExpression paramExpr, ConstantExpression valueExpr) { 
    var memberAcc = Expression.MakeMemberAccess(paramExpr, prop); 
    Console.WriteLine(memberAcc); 
    var containsMember = typeof(string).GetMethod("Contains"); 
    var toLower= typeof(String).GetMethod("ToLower",new [] {typeof(string)}); 
    var ttt=Expression.Call(memberAcc,containsMember, valueExpr); 
    return Expression.Call(memberAcc,containsMember, valueExpr); 
} 
+1

那你试试这么远吗?你卡在哪里? – Icepickle

+0

我一直在尝试写这样的代码来过滤任何List.it的作品,但在大写 –

+0

私有静态表达GetPropertyExpression(的PropertyInfo道具,ParameterExpression paramExpr,常量表达式valueExpr) \t { \t \t VAR memberAcc = Expression.MakeMemberAccess(paramExpr,道具); \t \t // Console.WriteLine(memberAcc); \t \t var containsMember = typeof(string).GetMethod(“Contains”); var toLower = typeof(String).GetMethod(“ToLower”,new [] {typeof(string)}); \t \t var ttt = Expression.Call(memberAcc,containsMember,valueExpr); \t \t return Expression.Call(memberAcc,containsMember,valueExpr); \t} –

回答

1

你可以自己做的稍微容易。除了使用Contains方法,其中有趣的是不支持StringComparison作为参数传递,您可以使用IndexOf方法。

你可以像这样实现:

public static Expression<Func<T, bool>> ContainsValue<T>(string fieldName, string val) { 
    var type = typeof(T); 
    var member = Expression.Parameter(type, "param"); 
    var memberExpression = Expression.PropertyOrField(member, fieldName); 
    var targetMethod = memberExpression.Type.GetMethod("IndexOf", new Type[] { typeof(string), typeof(StringComparison) }); 
    var methodCallExpression = Expression.Call(memberExpression, targetMethod, Expression.Constant(val), Expression.Constant(StringComparison.CurrentCultureIgnoreCase)); 

    return Expression.Lambda<Func<T, bool>>( 
     Expression.AndAlso(
      Expression.NotEqual(memberExpression, Expression.Constant(null)), 
      Expression.GreaterThanOrEqual(methodCallExpression, Expression.Constant(0)) 
     ), 
     member 
    ); 
} 

这里的技巧是,我结合IndexOf方法与GreaterThanOrEqual呼叫与中端的0.1

该值给出了一个测试类下面的表达式

((param.Parameter != null) AndAlso (param.Parameter.IndexOf("test", CurrentCultureIgnoreCase) >= 0)) 

一个例子,你可以在这里找到在dotnetfiddle,但我还添加了完整的代码BEL流

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 

public class Program 
{ 
    public static Expression<Func<T, bool>> ContainsValue<T>(string fieldName, string val) { 
     var type = typeof(T); 
     var member = Expression.Parameter(type, "param"); 
     var memberExpression = Expression.PropertyOrField(member, fieldName); 
     var targetMethod = memberExpression.Type.GetMethod("IndexOf", new Type[] { typeof(string), typeof(StringComparison) }); 
     var methodCallExpression = Expression.Call(memberExpression, targetMethod, Expression.Constant(val), Expression.Constant(StringComparison.CurrentCultureIgnoreCase)); 

     return Expression.Lambda<Func<T, bool>>( 
      Expression.AndAlso(
       Expression.NotEqual(memberExpression, Expression.Constant(null)), 
       Expression.GreaterThanOrEqual(methodCallExpression, Expression.Constant(0)) 
      ), 
      member 
     ); 
    } 

    public static void Main() 
    { 
     var items = new List<Test>() { 
      new Test() { Parameter = "Alpha" }, 
      new Test(), 
      new Test() { Parameter = "Test" }, 
      new Test() { Parameter = "test" }, 
      new Test() { Parameter = "TEST" }, 
      new Test() { Parameter = "Contains test" } 
     }; 
     var expr = ContainsValue<Test>("Parameter", "test"); 
     // you can see the body here 
     Console.WriteLine(expr.Body); 
     // and the result 
     var results = items.Where(expr.Compile()).Select(t => t.Parameter).ToList(); 
     Console.WriteLine("Results: {0}", string.Join(",", results)); 
     Console.WriteLine("Total results: {0}", results.Count); 
    } 

    public class Test { 
     public string Parameter { get;set; } 
    } 
} 

输出:

((param.Parameter != null) AndAlso (param.Parameter.IndexOf("test", CurrentCultureIgnoreCase) >= 0)) 
Results: Test,test,TEST,Contains test 
Total results: 4 
+0

感谢Icepickle,我希望它适用于像字符串,小数,双打等常见数据类型的类。目前它的效果非常好,但只在字符串字段 –

+0

@EmmanuelOgoma这当然是可能的,因为有很多不同的表达式可用。但是,例如,他们没有Contains方法,还有很多工作要做。根据你希望如何将表达式组合起来,它可能是一些工作;) – Icepickle

+0

这个lambda运作,但我不知道如何创建它的表达式。注意一个名为x => x.FieldName!= null && x.FieldName.Tostring()。ToLower()的Tostring方法。包含(参数) –