Разрешение на создание в методе расширения

#c# #extension-methods

#c# #методы расширения

Вопрос:

У меня есть класс со свойством IList, доступным только для чтения. Я создал простой метод расширения, AddCSV, для добавления нескольких элементов в этот список. Я хочу создать делегат действия для заполнения списка с помощью метода расширения. До сих пор у меня есть

 private Action<TListPropertyContainer, TDataValue> CreateListPropertySetter<TListPropertyContainer, TDataValue>(string listName)
{
    var list = typeof(TListPropertyContainer).GetProperty(listName);
    var method = typeof(Extensions).GetMethod("AddCSV");
    return (Action<TListPropertyContainer, TDataValue>)Delegate.CreateDelegate(typeof(Action<TListPropertyContainer, TDataValue>), list, method);
}
  

но, очевидно, это не работает!

Я знаю, что есть другие варианты. Например, а) я мог бы наследовать список в свой собственный класс customer и добавить туда AddCSV б) Я мог бы заставить свойство items читать / записывать и установить полностью заполненный список в свой класс

Я был бы признателен, если бы кто-нибудь мог меня поправить.

Большое спасибо

Саймон

Ответ №1:

Есть две основные проблемы.

  1. Вы пытаетесь вызвать метод в PropertyInfo , а не в списке. Чтобы получить значение свойства, вам нужно будет выполнить вызов GetValue()

  2. Вызов GetMethod() не указывает флаги привязки. Я подозреваю, что это могло бы работать лучше с GetMethod("AddCSV", BindingFlags.Public | BindingFlags.Static) .

При этом, почему вы создаете его рефлексивно, когда вы заранее знаете тип и метод? Кажется, что вы могли бы просто сделать:

  private Action<TListPropertyContainer, TDataValue> CreateListPropertySetter<TListPropertyContainer, TDataValue>(string listName)
 {
       var propertyInfo = typeof(TListPropertyContainer).GetProperty(listName);
       return (container,value) => {
            var list = (IList<TDataValue>)propertyInfo.GetValue(container,null);
            list.AddCSV(list);
       };
  }
  

Если я делаю неверные предположения о сигнатуре метода расширения или типе свойства, вы все равно можете сделать это с помощью Delegate.CreateDelegate() , но примите во внимание комментарии о PropertyInfo и the BindingFlags

Комментарии:

1. Большое спасибо. Вы были правы, и я слишком все усложнил! Ваш пример кода сделал свое дело.

Ответ №2:

Вы пытаетесь использовать list в качестве целевого делегата — но list имеет тип PropertyInfo , который звучит так, как будто это не то, что вы ожидали. Предполагая, что вы хотите получить значение свойства, а затем вызвать для этого метод, вам также нужно передать объект, содержащий свойство, чтобы вы могли получить фактический список. (В качестве альтернативы, может быть, это «это» — вы действительно не прояснили это.) В любом случае, вы можете получить сам список и использовать его в качестве целевого. Например:

 private Action<TListPropertyContainer, TDataValue> 
    CreateListPropertySetter<TListPropertyContainer, TDataValue>
    (string listName, object target)
{
    var listProperty = typeof(TListPropertyContainer).GetProperty(listName);
    object list = listProperty.GetValue(target, null);
    var method = typeof(Extensions).GetMethod("AddCSV");
    return (Action<TListPropertyContainer, TDataValue>)Delegate.CreateDelegate(
        typeof(Action<TListPropertyContainer, TDataValue>), list, method);
}
  

Если это не помогло, пожалуйста, отредактируйте свой вопрос с помощью короткого, но полного консольного приложения, демонстрирующего проблему. Прямо сейчас слишком много неизвестных, чтобы определенно помочь вам.

Комментарии:

1. Спасибо, Джон. Я вижу свою ошибку из того, что вы говорите. Я подготовлю пример. Проблема здесь в том, что я буду передавать экземпляр при вызове делегата, а не при его создании