Делегат для общего свойства. GetSetMethod - PullRequest
6 голосов
/ 11 ноября 2011

Я пытаюсь создать делегата для установки значения свойства универсального, но я получаю ошибку: Error binding to target method при попытке выполнить следующий код:

Action<T, object> setValue = (Action<T, object>) Delegate.CreateDelegate(
    typeof(Action<T, object>), null, property.GetSetMethod());

Возможно ли это вообще?

Ответы [ 3 ]

3 голосов
/ 11 ноября 2011

Да, возможно, вы просто пытаетесь создать делегата неправильного типа.Метод set свойства принимает только один аргумент, значение, которое вы собираетесь установить.Кроме того, поскольку это метод экземпляра, вы должны передать целевой объект, с которым вы хотите связать его, в вызове CreateDelegate.

Пример:

  var setValue = (Action<T>)Delegate.CreateDelegate( typeof( Action<T> ), target, property.GetSetMethod() );
1 голос
/ 22 апреля 2013

Это зависит. В своем ответе я предполагаю две вещи:

  1. Ваш тип "T" - это тип вашего класса (который я сейчас обозначу как TClass)
  2. Тип "объект" - это тип вашей собственности (который я сейчас обозначу как TProperty)

Поскольку ваша собственность нестатическая, есть две возможности:

  1. «Обычный» делегат с прикрепленной целью (экземпляром).
  2. «Открытый» делегат, в котором цель является первым входным параметром делегата.

Функция для создания такого «нормального» делегата создается следующим образом:

static public Action<TClass, TProperty> CreateSetPropertyDelegate<TClass, TProperty>(this PropertyInfo propertyInfo)
{
    return (Action<TClass, TProperty>)Delegate.CreateDelegate(typeof(Action<TClass, TProperty>), propertyInfo.GetSetMethod());
}

И используется (при условии, что тип свойства имеет тип int):

Action<int> setter = typeof(MyClass).GetProperty("MyProperty").CreateSetPropertyDelegate<MyClass, int>(myInsance);
setter(myPropertyValue);

Функция для создания открытого делегата:

static public Action<TClass, TProperty> CreateSetPropertyDelegate<TClass, TProperty>(this PropertyInfo propertyInfo)
{
    return (Action<TClass, TProperty>)Delegate.CreateDelegate(typeof(Action<TClass, TProperty>), propertyInfo.GetSetMethod());
}

и используется:

Action<MyClass, int> setter = typeof(MyClass).GetProperty("MyProperty").CreateSetPropertyDelegate<MyClass, int>();
setter(myInsance, myPropertyValue);
1 голос
/ 11 ноября 2011

Я думаю, вы хотите это:

Action<T, object> setValue = (t, o) => property.GetSetMethod().Invoke(t, new object[] { o });

или

Action<T, object> setValue = (t, o) => property.SetValue(t, o, null);

EDIT

Чтобы проиллюстрировать предполагаемую худшую эффективность этого ответа по сравнению с принятым ответом, предположим этот метод:

void SetAnObjectPropertyOnALotOfObjects<T>(IEnumerable<T> objs)
{
    //Create a delegate and assign a reference to that delegate to the setValue variable
    Action<T, object> setValue = GetSetter();

    foreach (var o in objs)
    {
        //invoke the delegate referred to by the setValue variable (that is, "invoke its referent"
        setValue.Invoke(o, new object());
    }
}

Ответ MerickOWA использует отражение в методе GetSetter, поэтому мы предполагаем, что метод GetSetter требует больше времени для выполнения, в его подходе. Этот ответ использует отражение каждый раз, когда мы вызываем setValue.Invoke, поэтому мы предполагаем, что выполнение этого ответа занимает больше времени. Если мы предположим, что количество элементов в последовательности велико, для ответа MerickOWA потребуется меньше времени.

Например, предположим, что метод GetSetter MerickOWA занимает X миллисекунд больше, чем мой, в то время как мой делегат setValue занимает Y миллисекунд больше, чем его. Если в последовательности N элементов, то мое решение должно быть медленнее, чем его (N * Y - X) миллисекунд.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...