6 votes

Comment construire une Expression<Func<T,bool>> à partir d'une Expression<Func<T>>.

Y a-t-il un moyen de construire Expression<Func<T,bool>> de Expression<Func<T>> ?

Par exemple, pour la classe

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

si Expression<Func<T>> es () => new MyClass{Prop2 = 5} alors le résultat devrait être x => x.Prop2 == 5

si Expression<Func<T>> es () => new MyClass{Prop1 = 1, Prop3 = 3} alors le résultat devrait être x => x.Prop1 == 1 && x.Prop3 == 3

En d'autres termes, est-il possible de créer une fonction avec un nombre quelconque de conditions au moment de l'exécution ?

7voto

Marc Gravell Points 482669

Comme ça :

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);
}

2voto

Lolo Points 8894

Laissons le code parler pour lui-même :

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));
        }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X