Questo sarebbe molto semplice se potessi assegnare tramite un'espressione Lambda (sotto)
//An expression tree cannot contain an assignment operator
Expression<Func<ComplexObj, object>> expression = obj => obj.Contacts[0].FirstName = "Tim";
Questo codice sopra non è valido a causa dell'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);
}
Aggiornare:
"passare un'assegnazione di proprietà a un metodo come un albero di espressioni ..."
Utilizzando il metodo SetValue con ParentTypeA, Value non funzionerà. (sotto il 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);
}
Ho finito per utilizzare la seguente soluzione. Saluti
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);
}
La domanda collegata è probabilmente la risposta "giusta", ma solo per completezza, si potrebbe fare qualcosa di più simile ... segue la metodologia "tell, do not ask" un po 'meglio, anche se io non posso dire che mi piace l'implementazione ...
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; }
}