Создание делегата метода set свойства

Я создал методы для преобразования лямбды свойства делегату:

public static Delegate MakeGetter<T>(Expression<Func<T>> propertyLambda)
{
    var result = Expression.Lambda(propertyLambda.Body).Compile();
    return result;
}

public static Delegate MakeSetter<T>(Expression<Action<T>> propertyLambda)
{
    var result = Expression.Lambda(propertyLambda.Body).Compile();
    return result;
}

Они работают:

Delegate getter = MakeGetter(() => SomeClass.SomeProperty);
object o = getter.DynamicInvoke();

Delegate getter = MakeGetter(() => someObject.SomeProperty);
object o = getter.DynamicInvoke();

но они не скомпилируют:

Delegate setter = MakeSetter(() => SomeClass.SomeProperty);
setter.DynamicInvoke(new object[]{propValue});

Delegate setter = MakeSetter(() => someObject.SomeProperty);
setter.DynamicInvoke(new object[]{propValue});

Сбой строк MakeSetter с "Аргументами типа не может быть выведен из использования. Попытайтесь указать аргументы типа явно".

То, что я пытаюсь сделать возможный?Заранее спасибо.

36
задан Jim C 12 May 2010 в 22:33
поделиться

3 ответа

Ваш MakeSetter ожидает Action , а вы передаете ему Func ( () => someObject. SomeProperty ). Попробуйте следующее:

Delegate setter = MakeSetter((prop) => {someObject.SomeProperty = prop;});
setter.DynamicInvoke(new object[]{propValue});

EDIT Не похоже, что вы можете преобразовать лямбда-выражения операторов в выражения . Это своего рода обходной способ сделать это без выражений - прямо к делегатам:

class Test2 {
    delegate void Setter<T>(T value);

    public static void Test() {
        var someObject = new SomeObject();
        Setter<string> setter = (v) => { t.SomeProperty = v; };
        setter.DynamicInvoke(new object[]{propValue});
    }
}
4
ответ дан 27 November 2019 в 05:34
поделиться

Action представляет делегата, который принимает один параметр типа T и ничего не возвращает. Лямбда-выражения, которые вы предоставляете для MakeSetter , представляют делегатов, которые не принимают параметров и возвращают либо SomeClass.SomeProperty , либо someObject.SomeProperty .

Сообщения об ошибках, которые вы получаете, связаны с тем, что компилятор не может вывести типы из лямбда-выражений, которые вы передаете в метод MakeSetter , потому что то, что вы передали, и какой метод ожидает, не синхронизированы.

4
ответ дан 27 November 2019 в 05:34
поделиться

API Expression поддерживает это в .NET 4.0, но, к сожалению, компилятор C# не добавляет никаких дополнительных конфет для поддержки. Но есть и хорошая новость: вы можете тривиально взять выражение "get" (которое компилятор C# может написать) и переписать его как выражение "set".

И даже лучше: если у вас нет .NET 4.0, есть еще как минимум два способа выполнить "set" через выражение, написанное как "get".

Вот они, для информации:

using System;
using System.Linq.Expressions;
using System.Reflection;
class Foo {
    public string Bar { get; set; }
    static void Main() {
        // take a "get" from C#
        Expression<Func<Foo, string>> get = foo => foo.Bar;

        // re-write in .NET 4.0 as a "set"
        var member = (MemberExpression)get.Body;
        var param = Expression.Parameter(typeof(string), "value");
        var set = Expression.Lambda<Action<Foo, string>>(
            Expression.Assign(member, param), get.Parameters[0], param);

        // compile it
        var action = set.Compile();
        var inst = new Foo();
        action(inst, "abc");
        Console.WriteLine(inst.Bar); // show it working

        //==== reflection
        MethodInfo setMethod = ((PropertyInfo)member.Member).GetSetMethod();
        setMethod.Invoke(inst, new object[] { "def" });
        Console.WriteLine(inst.Bar); // show it working

        //==== Delegate.CreateDelegate
        action = (Action<Foo, string>)
            Delegate.CreateDelegate(typeof(Action<Foo, string>), setMethod);
        action(inst, "ghi");
        Console.WriteLine(inst.Bar); // show it working
    }
}
57
ответ дан 27 November 2019 в 05:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: