如何构建表达式<func <t,bool>&gt;来自Expression <func <t>&gt; </func <t> </func <t,bool>

时间:2012-12-07 07:11:06

标签: c# .net linq linq-expressions

有没有办法从Expression<Func<T,bool>>构建Expression<Func<T>>

例如对于班级

public class MyClass
{
    public int Prop1{get;set;}
    public int Prop2{get;set;}
    public int Prop3{get;set;}
}

如果Expression<Func<T>>() => new MyClass{Prop2 = 5},则结果应为x => x.Prop2 == 5

如果Expression<Func<T>>() => new MyClass{Prop1 = 1, Prop3 = 3},则结果应为x => x.Prop1 == 1 && x.Prop3 == 3

换句话说,是否可以在运行时创建具有任意数量条件的func?

2 个答案:

答案 0 :(得分:7)

像这样:

static Expression<Func<T,bool>> Munge<T>(Expression<Func<T>> selector)
{
    var memberInit = selector.Body as MemberInitExpression;
    if (memberInit == null)
        throw new InvalidOperationException("MemberInitExpression is expected");
    var p = Expression.Parameter(typeof(T), "x");

    Expression body = null;
    foreach (MemberAssignment binding in memberInit.Bindings)
    {
        var comparer = Expression.Equal(
            Expression.MakeMemberAccess(p, binding.Member),
            binding.Expression);
        body = body == null ? comparer : Expression.AndAlso(body, comparer);
    }
    if (body == null) body = Expression.Constant(true);

    return Expression.Lambda<Func<T, bool>>(body, p);
}

答案 1 :(得分:2)

让代码为自己说话:

class Program
{
    static Expression<Func<T, bool>> Transform<T>(Expression<Func<T>> expression)
    {
        var initExpression = expression.Body as MemberInitExpression;
        if (initExpression == null)
        {
            throw new ArgumentException();
        }

        Expression bodyExpression = Expression.Constant(true);
        IEnumerable<MemberBinding> bindings = initExpression.Bindings;
        ParameterExpression param = Expression.Parameter(typeof(T));

        foreach (var memberBinding in bindings)
        {
            var memberAssigment = memberBinding as MemberAssignment;
            if (memberAssigment == null)
            {
                throw new ArgumentException();
            }

            var member = memberAssigment.Member;
            var value = memberAssigment.Expression;

            bodyExpression = Expression.AndAlso(
                bodyExpression,
                Expression.Equal(
                    Expression.MakeMemberAccess(param, member),
                    value
                )
            );
        }

        return Expression.Lambda<Func<T, bool>>(bodyExpression, param);
    }

    static void Main(string[] args)
    {
        Expression<Func<MyClass>> exp = () => new MyClass { Prop1 = 1, Prop3 = 3 };

        var result = Transform(exp);
        var lambda = result.Compile();

        var array = new[]
        {
            new MyClass { Prop1 = 1, Prop3 = 3 },
            new MyClass { Prop1 = 1, Prop2 = 2, Prop3 = 3 },
            new MyClass { Prop1 = 1, Prop3 = 1 },
            new MyClass { Prop1 = 3, Prop3 = 3 },
            new MyClass { Prop1 = 3, Prop3 = 1 },
            new MyClass()
        };

        foreach (var o in array)
        {
            Console.WriteLine(lambda(o));
        }
    }
}