2017-10-04 2 views
2

Ist es möglich, eine ausgewählte Projektion zu einem bestimmten Zeitpunkt auszuwerten, um eine Liste der ausgewählten Eigenschaften zu erhalten?Auswertung ausgewählter Projektion

Zum Beispiel, wenn ich die folgende Klasse:

public class Example() 
{ 
    public string Aaa { get; set; } 

    public int Bbb { get; set; } 

    public string Ccc { get; set; } 
} 

und die folgende Auswahl Projektion:

Expression<Func<Example, Example>> select = x => new Example { Aaa= x.Aaa, Ccc = x.Ccc }; 

Wäre es möglich, die Auswahl Projektion zu interpretieren ein Ergebnis entlang der Linien zu erhalten von var result = new List<string> { "Aaa", "Ccc" };?

+0

wollen Sie damit sagen Sie die Lambda des Parse-Baum gehen wollen und rufen Sie eine Liste th Die Namen aller Eigenschaften, auf die der Code verweist? Wenn ja, kann das gemacht werden. –

+0

Ein Prädikat ist eine Funktion, die einen booleschen Wert erzeugt. Das ist eine Projektion (etwas, das einen Wert in einen anderen Werttyp umwandelt). – Servy

+0

@EdPlunkett Das klingt nach richtig. Wie würde ich das machen? Ich habe versucht, die Bindungen [] zur Laufzeit auszuwerten, jedoch sind die Werte geschützt und können außerhalb der Uhr/Quickwatch nicht zugegriffen werden. – Ebbs

Antwort

3

Der beste Weg, um so etwas zu tun, ist ein ExpressionVisitor. Hier

ein Beispiel:

public class MyMemberExpressionVisitor : ExpressionVisitor 
{ 
    protected override Expression VisitMember(MemberExpression node) 
    { 
     if (node.Member.MemberType == MemberTypes.Property // is a property 
      && node.Expression.NodeType == ExpressionType.Parameter // is from a parameter expression 
      && Members.All(s => s != node.Member.Name)) // avoids duplicates 
     { 
      Members.Add(node.Member.Name); 
     } 

     return base.VisitMember(node); 
    } 

    public List<string> Members { get; set; } = new List<string>(); 
} 

Dann können Sie es wie folgt verwenden:

// Complex expressions work too! 
Example outsideExample = new Example(); 
Expression<Func<Example, Example>> expression = x => new Example(
    x.Aaa + outsideExample.Bbb, 
    x.Ccc + x.Aaa.Length); 

var myVisitor = new MemberExpressionVisitor(); 
myVisitor.Visit(expression); 
Console.WriteLine(string.Join(", ", myVisitor.Members)); // This should print out "Aaa, Ccc" 

Sie können How to: Implement an Expression Tree Visitor besuchen, um mehr zu lernen, wie man implementieren.

+0

Beachten Sie, dass nicht alle Mitglieder Eigenschaften sind. – Servy

+0

Natürlich ... Es kann verbessert werden! :) –

-2

Um alle der Eigenschaftsausdrücke in diesem Ausdruck finden können Sie einen ExpressionVisitor verwenden alle die Expression Instanzen innerhalb eines bestimmten Ausdruck zu inspizieren und die sind geistiges Eigentum zugreift und welche Eigenschaft zugegriffen wird sehen:

internal class PropertySearchVisitor : ExpressionVisitor 
{ 
    private List<MemberInfo> properties = new List<MemberInfo>(); 
    public IEnumerable<MemberInfo> Properties => properties; 
    protected override Expression VisitMember(MemberExpression node) 
    { 
     if (node?.Member?.MemberType == MemberTypes.Property) 
      properties.Add(node.Member); 
     return base.VisitMember(node); 
    } 
} 

Sobald Sie, dass Sie eine Methode schreiben können, einen bestimmten Ausdruck und geben die Eigenschaften (oder Eigenschaftsnamen) dieser Ausdruck zu besuchen:

public static IEnumerable<MemberInfo> GetProperties(this Expression expression) 
{ 
    var visitor = new PropertySearchVisitor(); 
    visitor.Visit(expression); 
    return visitor.Properties; 
} 
public static IEnumerable<string> GetPropertyNames(this Expression expression) 
{ 
    var visitor = new PropertySearchVisitor(); 
    visitor.Visit(expression); 
    return visitor.Properties.Select(property => property.Name); 
}