Func <> присваивает значение результату - PullRequest
2 голосов
/ 14 января 2011

То, что я пытаюсь сделать, кажется простым, но я не могу найти способ. Предположим, у меня есть метод с такой подписью:

public void Foo<T,K>(Expression<Func<T,K>> binding, T item, K value)

В моем методе я хочу сделать следующее: применить Func к элементу, получить свойство типа K, на которое указывает выражение привязки, и присвоить ему «значение».

Если выражение привязки выглядит примерно так:

c => c.Property

Где "c" - это "T", а "Property" - это "K", я могу легко использовать некоторое отражение и установить значение с помощью FieldInfo. Работает следующий код:

(((binding as LambdaExpression).Body as MemberExpression).Member as FieldInfo).SetValue(item, value);

Но выражение может быть примерно таким:

c => c.SubClass.Property

или

c => c.SubClass1.SubClass2.SubClassN.Property

В этом случае код отражения не работает, так как «Свойство» не принадлежит непосредственно T, но это все еще допустимое лямбда-выражение для сигнатуры метода.

Я знаю, что если я скомпилирую Func и выполню его на своем элементе типа TI, получу свойство, но оно будет похоже на его «копию», а не на ссылку, поэтому даже если я присваиваю ему значение свойство исходного элемента не изменяется.

Если у кого-то есть чистое решение для этого или просто укажите мне на что-то, что может дать мне лучшее знание Деревьев Выражений, очень приветствуем.

Ответы [ 2 ]

3 голосов
/ 14 января 2011

Звучит так, будто вы на самом деле не хотите, чтобы буква K была обозначена буквой T, но вместо этого вы хотите присвоить букву K той букве, о которой знает T, верно?

public void Foo<T,K>(Action<T,K> binding, T item, K value)
{
    binding(item, value);
}

Кажется более правильнымпотому что связывание - это делегат, который может взять T и сказать T, чтобы он правильно делал с K, верно?Назовите это так?

Foo<T,K>((t, k) => t.SubClass.Property = k, aT, aK);
2 голосов
/ 14 января 2011
static void AssignValue<TSource, TResult>(Expression<Func<TSource, TResult>> expression, TSource source, TResult result)
{
    var paramExp = expression.Parameters.Single();
    var assignExp = Expression.Assign(expression.Body, Expression.Constant(result));
    var lambdaExp = Expression.Lambda(assignExp, paramExp);
    lambdaExp.Compile().DynamicInvoke(source);
}

Использование:

 class Product
 {
    public int ID { get; set; }
    public string Name { get; set; }
 }

 var product = new Product { ID = 99, Name = "haha" };
 AssignValue<Product, string>(p => p.Name, product, "changed");
...