Подтвердить что ты не робот

Селектор свойств Expression <Func <T>>. Как получить/установить значение для выбранного свойства

У меня есть объект, который я хочу построить таким образом:

var foo = new FancyObject(customer, c=>c.Email); //customer has Email property

Как объявить второй параметр?

Как будет выглядеть код, который будет обращаться к выбранному устройству/получателю свойств?

Upd. В модели есть несколько объектов, у которых есть свойство Email. Вероятно, подпись будет выглядеть так:

public FancyObject(Entity holder, Expression<Func<T>> selector)

и вызов конструктора

var foo = new FancyObject(customer, ()=>customer.Email);
4b9b3361

Ответ 1

Параметр будет Expression<Func<Customer,string>> selector. Чтение может осуществляться с помощью плоской компиляции:

 Func<Customer,string> func = selector.Compile();

тогда вы можете получить доступ к func(customer). Назначение сложнее; для простых селекторов вы можете надеяться, что вы можете просто разложить на:

var prop = (PropertyInfo)((MemberExpression)selector.Body).Member;
prop.SetValue(customer, newValue, null);

Однако для более сложных выражений потребуется либо ручное древовидное движение, либо некоторое выражение 4.0 node -types:

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

Ответ 2

Похоже, что тип должен быть общим с двумя параметрами типа - источником и результатом. Например, вы можете использовать:

var foo = new FancyObject<Customer, string>(customer, c => c.Email);

Первый параметр будет иметь тип TSource, а второй будет 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;
    }
}

Вы можете сделать это проще для использования со статическим методом в неэквивалентном типе:

var foo = FancyObject.Create(customer, c => c.Email);

Это может использовать вывод типа для определения аргументов типа.