Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build Expression<Func<T,bool>> from Expression<Func<T>>

Is there a way to build Expression<Func<T,bool>> from Expression<Func<T>>?

For example for class

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

if Expression<Func<T>> is () => new MyClass{Prop2 = 5} then result should be x => x.Prop2 == 5

if Expression<Func<T>> is () => new MyClass{Prop1 = 1, Prop3 = 3} then result should be x => x.Prop1 == 1 && x.Prop3 == 3

In other words is it possible to create func with any number of conditions at runtime?

like image 840
VladK Avatar asked Dec 07 '12 07:12

VladK


2 Answers

Like this:

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);
}
like image 61
Marc Gravell Avatar answered Sep 18 '22 16:09

Marc Gravell


Let's the code speak for himself:

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));
        }
    }
}
like image 21
Krzysztof Avatar answered Sep 21 '22 16:09

Krzysztof