2008-10-26 9 views
30

Ich analysiere einen Ausdrucksbaum. Bei einem NodeType von ExpressionType.MemberAccess, wie bekomme ich den Wert dieses Feldes?Bei einem Typ ExpressionType.MemberAccess, wie bekomme ich den Feldwert?

Von C# MSDN-Dokumentation: MemberAccess ist ein Knoten, der das Lesen aus einem Feld oder einer Eigenschaft darstellt.

Ein Code-Snippet wäre unglaublich, unglaublich hilfreich. Danke im Voraus!!!

Mein Code sieht in etwa wie folgt aus:

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 
} 

Antwort

38

[für Klarheit aktualisiert]

Erste; Wirf die Expression auf eine MemberExpression.

A MemberExpression hat zwei Dinge von Interesse:

  • .Member - die PropertyInfo/FieldInfo dem Mitglied
  • Ausdrucks - der Ausdruck der "obj" für die .Member
  • zu bekommen, um zu bewerten

dh wenn Sie die .Expression auswerten können „obj“ und die .Member ist ein FieldInfo, dann können Sie den Istwert über .GetValue(obj) auf das bekommen FieldInfo (und PropertyInfo ist sehr ähnlich).

Das Problem ist, dass die .Expression Auswertung ist sehr schwierig ;-p

Offensichtlich Sie Glück haben, wenn es ein ConstantExpression erweist - aber in den meisten Fällen ist es nicht; Es könnte ein ParameterExpression sein (in diesem Fall müssen Sie den tatsächlichen Parameterwert kennen, den Sie auswerten möchten) oder eine andere Kombination von Expression s.

In vielen Fällen ist eine einfache (vielleicht faule) Option, .Compile() zu verwenden, um das .NET-Framework zu erhalten, das schwere Heben durchzuführen; Sie können das Lambda dann als typisierten Delegaten auswerten (indem Sie alle Parameter übergeben, die das Lambda benötigt). Dies ist jedoch nicht immer eine Option.

Um zu zeigen, wie komplex das ist; dieses triviales Beispiel betrachten (wo ich bei jedem Schritt hartcodiert haben, anstatt die Prüfung usw.):

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

Vielen Dank Marc. Der Wert der Eigenschaft .Expression ist ... etwas interessanter: \t {Wert (ASP.usercontrols_mycontro_ascx) .controlname} –

+0

Ich mache viel mit Generics und Reflexion, so dass das Abrufen des Wertes über propertinfo/fieldinfo nicht funktioniert, weil ich bin mir nicht sicher wo ich das referenzierende Objekt ziehen soll ... kann ich das von der memmerexpression oder methodinfo ziehen? –

+1

Es wird funktionieren ... aber das Problem ist, dass Sie das bewerten müssen.Ausdruck als Wert, der als "obj" für FieldInfo/PropertyInfo eingegeben wird. Kannst du nicht einfach .Compile() verwenden und das Lambda als Delegat ausführen? Viel einfacher als das Parsen ... –

21

danken Ihnen so viel über zu Marc GRA. Ich habe seine Hilfe sehr geschätzt.

Es stellt sich heraus, in meinem Fall. Das Problem kann gelöst werden über:

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

Danke nochmal Mark!

+0

genau das, was ich brauchte, aktualisieren! –

+5

oder besser 'Objekt Wert = Ausdruck.Lambda > (Ausdruck.Convert (expBody.Right, typeof (Objekt))). Compile(). Invoke()' –

+0

Der traurige Teil: es ist sehr langsam. – ren