#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:
Есть две основные проблемы.
-
Вы пытаетесь вызвать метод в
PropertyInfo
, а не в списке. Чтобы получить значение свойства, вам нужно будет выполнить вызовGetValue()
-
Вызов
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. Спасибо, Джон. Я вижу свою ошибку из того, что вы говорите. Я подготовлю пример. Проблема здесь в том, что я буду передавать экземпляр при вызове делегата, а не при его создании