Wie weise ich einen Wert über Expression zu?

c# expression-trees

Frage

Dies wäre sehr einfach, wenn ich über einen Lambda-Ausdruck (unten) zuordnen könnte

//An expression tree cannot contain an assignment operator
Expression<Func<ComplexObj, object>> expression = obj => obj.Contacts[0].FirstName = "Tim";

Dieser obige Code ist aufgrund des Zuweisungsoperators ungültig. Ich muss einen Lambda-Ausdruck übergeben, um die Eigenschaft in dem komplexen Objekt zu identifizieren, das gesetzt werden muss. In einigen Fällen hat das komplexe Objekt List und daher doppelte Objekttypen und Namen, weshalb ich das Lambda benötige, um explizit auf das Feld im zu aktualisierenden Objekt zu verweisen.

Ich bin in der Lage, den Wert mit den folgenden, kein Problem zu erhalten. Aber ich bin mir nicht sicher, wie man dieselbe Logik benutzt, um den Wert zu setzen, ich bin auf Expression.Assign gestoßen und glaube, dass dies die Lösung sein könnte.

Expression<Func<ComplexObj, object>> expression = obj => obj.Contacts[0].FirstName;
var result = FindByProperty(expression);

public static string FindByProperty(Expression<Func<Contract, object>> propertyRefExpr)
{
    ComplexObj obj = new ComplexObj();
    Contact myContact = new Contact();
    myContact.FirstName = "Allen";
    obj.Contacts = new List<Contact>{myContact};
    return propertyRefExpr.Compile().Invoke(obj);
}

Aktualisieren:

"Übergeben einer Eigenschaftszuweisung an eine Methode als Ausdrucksbaum ..."

Mit der SetValue-Methode mit ParentTypeA funktioniert Value nicht. (unter dem Code)

Expression<Func<ComplexObj, object>> expression = obj => obj.Contacts[0].FirstName;
obj.AssignNewValue(expression, firstName);

public static void AssignNewValue(this ComplexObj obj, Expression<Func<ComplexObj, object>> expression, object value)
{
    var propertyInfo = (PropertyInfo)((MemberExpression)expression.Body).Member;
    propertyInfo.SetValue(obj, value, null);
}

Akzeptierte Antwort

Ich habe die folgende Lösung verwendet. Prost

ComplexObj obj = new ComplexObj();
Expression<Func<ComplexObj, object>> expression = obj => obj.Contacts[index].FirstName;
obj.AssignNewValue(expression, firstName);

public static void AssignNewValue(this ComplexObj obj, Expression<Func<ComplexObj, object>> expression, object value)
{
    ParameterExpression valueParameterExpression = Expression.Parameter(typeof(object));
    Expression targetExpression = expression.Body is UnaryExpression ? ((UnaryExpression)expression.Body).Operand : expression.Body;

    var newValue = Expression.Parameter(expression.Body.Type);
    var assign = Expression.Lambda<Action<ComplexObj, object>>
                (
                    Expression.Assign(targetExpression, Expression.Convert(valueParameterExpression, targetExpression.Type)),
                    expression.Parameters.Single(),
                    valueParameterExpression
                );

    assign.Compile().Invoke(obj, value);
}

Beliebte Antwort

Die verknüpfte Frage ist wahrscheinlich die "richtige" Antwort, aber nur der Vollständigkeit halber könnte man etwas mehr so ​​machen ... es folgt der "Sag, frage nicht" -Methode ein bisschen besser, obwohl ich kann nicht sagen, dass ich die Implementierung mag ...

void Main()
{
    Expression<Func<ComplexObj, object>> expression = 
      obj => obj.Contacts[0].SetFirstName("Tim");       
}

public class ComplexObj
{
    public ComplexObj() { Contacts = new List<SimpleObj>(); }
    public List<SimpleObj> Contacts {get; private set;}
}
public class SimpleObj
{
    public string FirstName {get; private set;}
    public SimpleObj SetFirstName(string name) { this.FirstName = name; return this; }
}


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum