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.