2013-05-14 8 views
5

Wie erstelle ich einen Ausdruck, die folgende Ziel erfüllen wird:Dynamisch eine Eigenschaft String mit Expressions Auswertung

public object Eval(object rootObj, string propertyString)

zB: Eval(person, "Address.ZipCode") => return person.Address.ZipCode

Expression.PropertyOrField funktioniert nicht, weil ich nicht‘ t haben den Typ jeder Zwischeneigenschaft. Ich möchte vermeiden, eine Abhängigkeit von einer Skriptbibliothek zu erstellen.

Ich möchte versuchen, Ausdrücke zu verwenden, weil es mir erlauben würde, einen Cache dieser Ausdrucksbäume zu speichern, da sie mehrmals ausgeführt würden. Mir ist bewusst, dass dies iterativ oder rekursiv mit Reflektion möglich ist.

+0

Ich nehme an, Roslyn ist vom Tisch? –

Antwort

10

Es klingt wie Sie etwas wie folgt aussehen:

public object Eval(object root, string propertyString) 
{ 
    var propertyNames = propertyString.Split('.'); 
    foreach(var prop in propertyNames) 
    { 
     var property = root.GetType().GetProperty(prop); 
     if (property == null) 
     { 
      throw new Exception(...); 
     } 

     root = property.GetValue(root, null); 
    } 

    return root; 
} 

dies eine Expression Gebrauch zu erstellen:

public Expression Eval(object root, string propertyString) 
{ 
    var propertyNames = propertyString.Split('.'); 
    ParameterExpression param = Expression.Parameter(root.GetType, "_"); 
    Expression property = param; 
    foreach(var prop in propertyName) 
    { 
     property = Expression.PropertyOrField(property, prop); 
    } 

    return Expression.Lambda(property, param); 
} 
+0

+1 - Ich habe gerade an so etwas gearbeitet, aber du hast mich dazu geschlagen. – Bobson

+0

Das würde nicht funktionieren, da in dem Beispiel 'Person.Address.Zipcode' das Wurzelobjekt' Person' hat, das nicht 'Zipcode' als Eigenschaft hat - das ist eine Eigenschaft der Klasse/Struktur 'Adresse'. Ich denke also, rekursive Bewertung ist notwendig. –

+2

@JohnWillemse - "root" ändert sich bei jeder Iteration, also würde beim zweiten Durchlauf "Address" für "Zipcode" angezeigt. – Bobson

3

Hier ist eine rekursive Version des Codes des PSWG, mit Expressions Arbeits .

public Expression Eval(Expression expression, string property) 
{ 
    var split = property.Split('.'); 
    if (split.Length == 1) 
    { 
     return Expression.PropertyOrField(expression, property); 
    } 
    else 
    { 
     return Eval(Expression.PropertyOrField(expression, split[0]), property.Replace(split[0] + ".", "")); 
    } 
} 
+0

+1 Aber ich glaube nicht, dass Sie die Zeichenfolge jedes Mal teilen müssen, wenn Sie Rekursion verwenden. Sie können einfach 'property.IndexOf ('.')' Und 'property.Substring (...)' –

+0

@ p.s.w.g - Völlig wahr, und eine bessere Möglichkeit, es zu tun. Ich war nur faul. – Bobson