2008-10-26 12 views
30

Je suis en train d'analyser un arbre d'expression. Étant donné un NodeType d'ExpressionType.MemberAccess, comment obtenir la valeur de ce champ? A partir de C# MSDN docs: MemberAccess est un nœud qui représente la lecture d'un champ ou d'une propriété.Étant donné un type ExpressionType.MemberAccess, comment puis-je obtenir la valeur du champ?

Un extrait de code serait incroyablement, incroyablement utile. Merci d'avance!!!

Mon code ressemble à ceci:

public static List<T> Filter(Expression<Func<T, bool>> filterExp) 
{ 
//the expression is indeed a binary expression in this case 
BinaryExpression expBody = filterExp.Body as BinaryExpression; 

if (expBody.Left.NodeType == ExpressionType.MemberAccess) 
    //do something with ((MemberExpressionexpBody.Left).Name 

//right hand side is indeed member access. in fact, the value comes from //aspdroplist.selectedvalue    
if (expBody.Right.NodeType == ExpressionType.MemberAccess) 
{ 
    //how do i get the value of aspdroplist.selected value?? note: it's non-static       
} 

//return a list 
} 

Répondre

38

[mis à jour pour plus de clarté]

d'abord; transtypez Expression en MemberExpression.

Un MemberExpression a deux choses d'intérêt:

  • .member - le PropertyInfo/FieldInfo au membre
  • .Expression - l'expression d'évaluer pour obtenir le "obj" pour la .Membre

à savoir si vous pouvez évaluer le .Expression à « obj » et le .Member est un FieldInfo, alors vous pouvez obtenir la valeur réelle sur la via .GetValue(obj)FieldInfo (et PropertyInfo est très similaire).

Le problème est que l'évaluation de la .Expression est très délicat ;-P

Évidemment, vous avez de la chance si elle se révèle être une ConstantExpression - mais dans la plupart des cas il n'est pas; il peut s'agir d'un ParameterExpression (auquel cas vous devrez connaître la valeur réelle du paramètre que vous voulez évaluer), ou toute autre combinaison de Expression s.

Dans de nombreux cas, une option simple (peut-être paresseuse) consiste à utiliser .Compile() pour que le framework .NET effectue le gros du travail; vous pouvez ensuite évaluer le lambda en tant que délégué typé (en passant les paramètres requis par le lambda). Cependant, ce n'est pas toujours une option.

Pour montrer à quel point c'est complexe; Considérons cet exemple trivial (où je l'ai codé en dur à chaque étape, plutôt que de tester, etc.):

using System; 
using System.Linq.Expressions; 
using System.Reflection; 
class Foo 
{ 
    public string Bar { get; set; } 
} 

static class Program 
{ 
    static void Main() 
    { 
     Foo foo = new Foo {Bar = "abc"}; 
     Expression<Func<string>> func =() => foo.Bar; 

     MemberExpression outerMember = (MemberExpression)func.Body; 
     PropertyInfo outerProp = (PropertyInfo) outerMember.Member; 
     MemberExpression innerMember = (MemberExpression)outerMember.Expression; 
     FieldInfo innerField = (FieldInfo)innerMember.Member; 
     ConstantExpression ce = (ConstantExpression) innerMember.Expression; 
     object innerObj = ce.Value; 
     object outerObj = innerField.GetValue(innerObj); 
     string value = (string) outerProp.GetValue(outerObj, null);  
    } 

} 
+0

Merci beaucoup Marc. La valeur de la propriété .Expression est ... quelque chose de plus intéressant: \t {value (ASP.usercontrols_mycontro_ascx) .controlname} –

+0

Je fais beaucoup avec les génériques et la réflexion donc récupérer la valeur via propertyinfo/fieldinfo ne fonctionne pas parce que je Je ne suis pas sûr d'où tirer l'objet de référence de ... puis-je tirer cela de memberexpression ou methodinfo? –

+1

Cela fonctionnera ... mais le problème est que vous devez évaluer le.Expression en tant que valeur à fournir en tant que "obj" pour FieldInfo/PropertyInfo. Ne pouvez-vous pas simplement utiliser .Compile() et exécuter le lambda en tant que délégué? Beaucoup plus facile que l'analyse syntaxique ... –

21

Merci beaucoup à Marc Gravell ci-dessus. J'ai vraiment apprécié son aide.

Il s'avère, dans mon cas. le problème peut être résolu via:

object value = Expression.Lambda(expBody.Right).Compile().DynamicInvoke(); 

Merci encore Mark!

+0

juste ce dont j'avais besoin! –

+5

ou mieux 'objet valeur = Expression.Lambda > (Expression.Convert (expBody.Right, typeof (objet))). Compile(). Invoke()' –

+0

La partie triste: c'est très lent. – ren

Questions connexes