创建动态表达式树

时间:2017-05-14 16:31:10

标签: c# asp.net .net linq lambda

如何在C#

中将此Lambda转换为表达式树
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 个答案:

答案 0 :(得分: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方法与值为0的GreaterThanOrEqual调用结合起来。

这最终给出了表达式

之后的测试类
((param.Parameter != null) AndAlso (param.Parameter.IndexOf("test", CurrentCultureIgnoreCase) >= 0))

例如,你可以在dotnetfiddle找到,但我也在下面添加了完整的代码

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