2012-12-07 7 views
6

Questo sarebbe molto semplice se fossi in grado di assegnare tramite un'espressione lambda (sotto)Come assegnare un valore tramite Expression?

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

Questo codice è valido causa l'operatore di assegnazione. Devo passare un'espressione lambda per identificare la proprietà nell'oggetto complesso che deve essere impostato. In alcuni casi l'oggetto complesso ha List e quindi nomi e tipi di oggetti duplicati, motivo per cui ho bisogno che lambda faccia riferimento esplicitamente al campo nell'oggetto da aggiornare.

Sono in grado di recuperare il valore utilizzando il seguente, nessun problema. Ma non sono sicuro di come utilizzare questa stessa logica per impostare il valore, mi sono imbattuto in Expression.Assegna e credo che questa possa essere la soluzione.

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); 
} 

Aggiornamento:

"il superamento di un assegnazione di proprietà a un metodo come un albero di espressione ..."

Utilizzando il metodo SetValue con ParentTypeA, valore non funzionerà. (Di seguito Codice)

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); 
} 
+0

http://stackoverflow.com/questions/5780232/assign-property-with-an-expressiontree –

+0

questo sembra essere molto promettente Stan, grazie – AnxiousdeV

risposta

11

ho finito per usare la seguente soluzione. Acclamazioni

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); 
} 
0

Il legato-a mettere in discussione è probabilmente la risposta "giusta", ma solo per ragioni di completezza, si potrebbe fare qualcosa di più simile a questo ... si fa seguire la "raccontare , non chiedere" metodologia di un po 'meglio, anche se non posso dire che mi come l'attuazione ...

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; } 
} 
+0

Grazie Ger, questo funzionerebbe se la classe esistente erano più personalizzabile, tuttavia, questa classe è molto grande e l'implementazione sarebbe molto prolissa. – AnxiousdeV

+0

Sì, non posso dire che sia un'alternativa "buona", ma ero curioso di poter maneggiare l'espressione in modo tale da ottenere sia l'assegnazione che l'espressione "espressione" – JerKimball