6

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を作成することは可能ですか?

4

2 に答える 2

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);
}
于 2012-12-07T07:59:54.650 に答える
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));
        }
    }
}
于 2012-12-07T08:08:03.877 に答える