Приведение к общему списку переменных динамического типа - PullRequest
5 голосов
/ 15 октября 2011

Мне нужно изменить свойство Capacity динамической переменной типа List<*DynamicType*>. Проблема в том, что Activator возвращает переменную, object, если тип переменной не указан вместо List<*DynamicType*>, и лучшее, что я могу сделать, это привести ее к IList:

DynamicTypeBuilder builder = new DynamicTypeBuilder() { ... };
Type dataType = builder.GenerateType(...);
Type listDataType = typeof(List<>).MakeGenericType(dataType);
IList list = (IList)Activator.CreateInstance(listDataType);

После некоторых поисков я нашел только один взлом:

dynamic dynamicList = list;
dynamicList.Capacity = dataRowsCount;

Хотя это было бы приемлемо в моем случае, мне интересно, есть ли другой способ сделать это.

Ответы [ 2 ]

4 голосов
/ 15 октября 2011

Вы можете сделать это с помощью отражения:

var capacityProperty = listDataType.GetProperty("Capacity");
capacityProperty.SetValue(list, dataRowsCount, null);

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

3 голосов
/ 15 октября 2011

Возможно, это проще:

object list = Activator.CreateInstance(listDataType,
    new object[]{dataRowsCount});

Какой должен использовать правильный конструктор?

Дженерики и рефлексия - действительно боль в сочетании. Хак dynamic здесь не более уродлив, чем установка его с помощью отражения (магическая строка в виде литерала, против непроверенного члена свойства), а dynamic внутренне оптимизируется и кэшируется (для каждого типа), поэтому я бы не стал проблема с этим. Если вам нужно сделать больше, чем одно свойство, вы также можете использовать dynamic, чтобы перейти к универсальному методу, чтобы минимизировать уродливое:

void Evil<T>(List<T> list, int capacity) {
    list.Capacity = capacity;
    // do other stuff
}
...
dynamic list = Activator.CreateInstance(listDataType);
Evil(list, dataRowsCount);

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

...