Comment changer un type dans un arbre d’expression?

J’ai une méthode comme celle-ci:

private bool Method_1(Expression<Func> expression) { /* Some code that will call Method_2 */ } 

Dans cette méthode, je souhaite changer le type IPerson en un autre type. Je veux appeler une autre méthode qui ressemble à ceci:

 private bool Method_2(Expression<Func> expression) { /* Some code */ } 

Ainsi, dans method_1 je dois modifier IPerson en PersonData . Comment puis-je faire ceci?

Modifier:

Lorsque j’appelle: Method_1(p => p.Id == 1) je souhaite “enregistrer” la condition ( p.Id == 1 ), mais je souhaite l’exécuter sur un autre type, à savoir IPerson . Donc, je dois modifier l’expression ou créer une nouvelle expression avec IPerson

EDIT II:

Pour ceux qui sont intéressés, voici (pour l’instant) ma solution:

 private class CustomExpressionVisitor : ExpressionVisitor { ParameterExpression _parameter; public CustomExpressionVisitor(ParameterExpression parameter) { _parameter = parameter; } protected override Expression VisitParameter(ParameterExpression node) { return _parameter; } protected override Expression VisitMember(MemberExpression node) { if (node.Member.MemberType == System.Reflection.MemberTypes.Property) { MemberExpression memberExpression = null; var memberName = node.Member.Name; var otherMember = typeof(T).GetProperty(memberName); memberExpression = Expression.Property(Visit(node.Expression), otherMember); return memberExpression; } else { return base.VisitMember(node); } } } 

Et c’est comme ça que je l’utilise:

 public virtual bool Exists(Expression<Func> expression) { var param = Expression.Parameter(typeof(I)); var result = new CustomExpressionVisitor(param).Visit(expression.Body); Expression<Func> lambda = Expression.Lambda<Func>(result, param); bool exists = _repository.Exists(lambda); return exists; } 

C’est facile si vous utilisez .net 4 (mise à jour: comme indiqué dans le commentaire, ExpressionVisitor été ajouté à la version 4 et non à la version 4.5), il serait nécessaire de googler pour les anciens frameworks:

Il existe certaines hypothèses, mais je pense qu’elles sont valables pour votre scénario DTO et votre entité – les propriétés auxquelles vous accédez doivent correspondre.

 class PersonData { public bool Prop { get; set; } } interface IPerson { bool Prop { get; set; } } 

Dans la classe .net 4, une classe ExpressionVisitor définie facilite grandement la tâche si vous utilisez une version plus ancienne, vous devez écrire ou trouver son implémentation:

 class Visitor : ExpressionVisitor { ParameterExpression _parameter; //there must be only one instance of parameter expression for each parameter //there is one so one passed here public Visitor(ParameterExpression parameter) { _parameter = parameter; } //this method replaces original parameter with given in constructor protected override Expression VisitParameter(ParameterExpression node) { return _parameter; } //this one is required because PersonData does not implement IPerson and it finds //property in PersonData with the same name as the one referenced in expression //and declared on IPerson protected override Expression VisitMember(MemberExpression node) { //only properties are allowed if you use fields then you need to extend // this method to handle them if (node.Member.MemberType != System.Reflection.MemberTypes.Property) throw new NotImplementedException(); //name of a member referenced in original expression in your //sample Id in mine Prop var memberName = node.Member.Name; //find property on type T (=PersonData) by name var otherMember = typeof(T).GetProperty(memberName); //visit left side of this expression p.Id this would be p var inner = Visit(node.Expression); return Expression.Property(inner, otherMember); } } 

Preuve de concept:

 class Program { static void Main() { //sample expression Expression> expression = x => x.Prop; //parameter that will be used in generated expression var param = Expression.Parameter(typeof(PersonData)); //visiting body of original expression that gives us body of the new expression var body = new Visitor(param).Visit(expression.Body); //generating lambda expression form body and parameter //notice that this is what you need to invoke the Method_2 Expression> lambda = Expression.Lambda>(body, param); //compilation and execution of generated method just to prove that it works var boolValue = lambda.Comstack()(new PersonData()); } } 

Notez que cela fonctionnera pour les expressions simples. Si vous devez gérer x.Prop.Prop1 < 3 vous devez l'étendre davantage.