Comment construire une LambdaExpression à partir d’une LambdaExpression existante sans compilation

Je veux combiner deux LambdaExpressions sans les comstackr.

Voici à quoi ça ressemble si je les comstack:

public Expression<Func> CreatePredicate( Expression<Func> getMemberExpression, Expression<Func> memberPredicateExpression) { return x => memberPredicateExpression.Comstack()(getMemberExpression.Comstack()(x)); } 

Ce n’est évidemment pas le moyen le plus rapide d’obtenir l’expression cible à partir des arguments fournis. En outre, cela le rend incompatible avec des fournisseurs de requêtes tels que LINQ to SQL qui ne prennent pas en charge les appels de méthode C #.

D’après ce que j’ai lu, il semble que la meilleure approche consiste à créer une classe ExpressionVisitor . Cependant, cela semble être une tâche assez commune. Est-ce que quelqu’un connaît une base de code open source existante qui fournit ce type de fonctionnalité? Si non, quelle est la meilleure façon d’approcher ExpressionVisitor pour le rendre aussi générique que possible?

Je ne sais pas si c’est la meilleure façon, mais vous pourriez faire quelque chose comme ça:

 public Expression> CreatePredicate( Expression> getMemberExpression, Expression> memberPredicateExpression) { ParameterExpression x = Expression.Parameter(typeof(TContainer), "x"); return Expression.Lambda>( Expression.Invoke( memberPredicateExpression, Expression.Invoke( getMemberExpression, x)), x); } 

Usage:

 var expr = CreatePredicate( (Foo f) => f.Bar, bar => bar % 2 == 0); 

Résultat:

 x => Invoke(bar => ((bar % 2) == 0), Invoke(f => f.Bar, x)) 

J’imagine qu’il serait préférable d’obtenir quelque chose comme x => x.Bar % 2 == 0 , mais ce serait probablement beaucoup plus difficile …


EDIT: ce n’était pas si difficile avec un visiteur d’expression:

 public Expression> CreatePredicate( Expression> getMemberExpression, Expression> memberPredicateExpression) { return CombineExpressionVisitor.Combine( getMemberExpression, memberPredicateExpression); } class CombineExpressionVisitor : ExpressionVisitor { private readonly ParameterExpression _parameterToReplace; private readonly Expression _replacementExpression; private CombineExpressionVisitor(ParameterExpression parameterToReplace, Expression replacementExpression) { _parameterToReplace = parameterToReplace; _replacementExpression = replacementExpression; } public static Expression> Combine( Expression> memberSelector, Expression> resultSelector) { var visitor = new CombineExpressionVisitor( resultSelector.Parameters[0], memberSelector.Body); return Expression.Lambda>( visitor.Visit(resultSelector.Body), memberSelector.Parameters); } protected override Expression VisitParameter(ParameterExpression parameter) { if (parameter == _parameterToReplace) return _replacementExpression; return base.VisitParameter(parameter); } } 

Cela donne l’expression suivante:

 f => ((f.Bar % 2) == 0)