Expression <Func <T>> Property Selector. How to get / set the value for the selected property
I have an object that I want to build in this way:
var foo = new FancyObject(customer, c=>c.Email); //customer has Email property How to declare the second parameter?
What will the code look like that will access the selected device / property recipient?
Upd. There are several objects in the model that have the Email property. The signature will probably look like this:
public FancyObject(Entity holder, Expression<Func<T>> selector) and constructor call
var foo = new FancyObject(customer, ()=>customer.Email); The parameter will be Expression<Func<Customer,string>> selector . Reading can be done using flat compilation:
Func<Customer,string> func = selector.Compile(); then you can access func(customer) . Appointment is more complicated; for simple selectors, you can hope that you can simply decompose into:
var prop = (PropertyInfo)((MemberExpression)selector.Body).Member; prop.SetValue(customer, newValue, null); However, for more complex expressions, you will need either a manual tree-like movement or some 4.0 node -types expression:
Expression<Func<Customer, string>> email = cust => cust.Email; var newValue = Expression.Parameter(email.Body.Type); var assign = Expression.Lambda<Action<Customer, string>>( Expression.Assign(email.Body, newValue), email.Parameters[0], newValue); var getter = email.Compile(); var setter = assign.Compile(); It seems that the type should be shared with two type parameters - the source and the result. For example, you can use:
var foo = new FancyObject<Customer, string>(customer, c => c.Email); The first parameter will be of type TSource , and the second will be Expression<Func<TSource, TResult>> :
public class FancyObject<TSource, TResult> { private readonly TSource value; private readonly Expression<Func<TSource, TResult>> projection; public FancyObject(TSource value, Expression<Func<TSource, TResult>> projection) { this.value = value; this.projection = projection; } } You can make it easier to use with a static method in a nonequivalent type:
var foo = FancyObject.Create(customer, c => c.Email); This can use type inference to determine type arguments.