Есть ли доступный делегат для свойств в С#?

Учитывая следующий класс:

class TestClass {
  public void SetValue(int value) { Value = value; }
  public int Value { get; set; }
}

Я могу сделать

TestClass tc = new TestClass();
Action<int> setAction = tc.SetValue;
setAction.Invoke(12);

что все хорошо. Можно ли сделать то же самое, используя свойство вместо метода? Предпочтительно с чем-то встроенным в .net.

Ответы

Ответ 1

Вы можете создать делегат, используя отражение:

Action<int> valueSetter = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), tc, tc.GetType().GetProperty("Value").GetSetMethod());

или создать делегат для анонимного метода, который устанавливает свойство;

Action<int> valueSetter = v => tc.Value = v;

Изменить: использовать неправильную перегрузку для CreateDelegate(), нужно использовать ту, которая принимает и объект как цель. Фиксированный.

Ответ 2

Есть три способа сделать это; во-первых, использовать GetGetMethod()/GetSetMethod() и создать делегат с Delegate.CreateDelegate. Второй - лямбда (не очень полезно для отражения!) [Т. х = > x.Foo]. Третий - через выражение (.NET 3.5).

Лямбда - самый простой; -p

    class TestClass
    {
        public int Value { get; set; }
    }
    static void Main()
    {
        Func<TestClass, int> lambdaGet = x => x.Value;
        Action<TestClass, int> lambdaSet = (x, val) => x.Value = val;

        var prop = typeof(TestClass).GetProperty("Value");
        Func<TestClass, int> reflGet = (Func<TestClass, int>) Delegate.CreateDelegate(
            typeof(Func<TestClass, int>), prop.GetGetMethod());
        Action<TestClass, int> reflSet = (Action<TestClass, int>)Delegate.CreateDelegate(
            typeof(Action<TestClass, int>), prop.GetSetMethod());
    }

Чтобы показать использование:

        TestClass foo = new TestClass();
        foo.Value = 1;
        Console.WriteLine("Via property: " + foo.Value);

        lambdaSet(foo, 2);
        Console.WriteLine("Via lambda: " + lambdaGet(foo));

        reflSet(foo, 3);
        Console.WriteLine("Via CreateDelegate: " + reflGet(foo));

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

Ответ 3

Свойства действительно обертки вокруг методов в .Net, поэтому, используя отражение, вы должны иметь возможность получить делегат (set_PROPERTY и get_PROPERTY), а затем выполнить их...

См. System.Reflection.PropertyInfo

Если есть два метода, которые вы можете использовать для получения/установки значения - GetGetMethod и GetSetMethod.

Итак, вы можете написать:

var propertyInfo = typeof (TestClass).GetProperty ("Value");

var setMethod = property.GetSetMethod (); // This will return a MethodInfo class.