2011-10-15 16 views
5

Potrzebuję zmienić właściwość Capacity zmiennej dynamicznej typu List<*DynamicType*>. Problemem jest to, że Activator powraca object -casted jeśli zmienna zmienna typu nie jest określony, zamiast prawidłowego List<*DynamicType*> i najlepsze, co mogę zrobić, to oddać go do IList:Przesyłanie do ogólnej listy zmiennych typu dynamicznego

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

Po poszukiwaniach znalazłem tylko jeden Hack:

dynamic dynamicList = list; 
dynamicList.Capacity = dataRowsCount; 

Chociaż byłoby to do przyjęcia w moim przypadku, zastanawiam się, czy jest inny sposób, aby to zrobić.

Odpowiedz

3

Być może jest prostsze:

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

Który powinien używać odpowiedniego konstruktora?

Generics and reflection są w rzeczywistości połączeniem bólu. Hack tutaj jest nie brzydszy niż ustawienie go za pomocą odbicia (magiczny ciąg jako literał, a niezweryfikowany element właściwości), a dynamic jest wewnętrznie zoptymalizowany i buforowany (dla typu), więc nie miałbym z tym problemu . Jeśli trzeba zrobić więcej niż tylko jednej nieruchomości, można również użyć dynamic przerzucić do metody rodzajowej, aby zminimalizować brzydkie:

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

które wywoła metodę ogólną z prawidłowym T. Nie jest to warte tylko dla 1 członka, ale może być przydatne w przypadku bardziej złożonych scenariuszy.

+0

Zapomniałem o tym konstruktorze. Ponieważ muszę ustawić tylko tę właściwość, robienie tego w ten sposób jest naprawdę prostsze. I podoba mi się również twoja sugestia, aby użyć ogólnej metody do "rzucania" obiektu IList, bardzo miłego. –

+0

BTW, choć być może robię coś nie tak, ale przypisanie wyniku 'Activator.CreateInstance()' do zmiennej 'generic' w moim przypadku nie zadziała, ponieważ' list.Add (* Dynamicznie utworzony obiekt dataType *) ' powoduje wyjątek, a z pre-casting 'list' na' IList' działa. –

+0

@Dmitry pewnie, a następnie odrzuć do "IList". Nie zrobiłem tego w tym przykładzie, po prostu dlatego, że ilustrowałem minimum, aby wykonać operacje * w przykładzie *, a przykład nie ma 'Dodaj (...)' –

4

Można zrobić to z refleksji:

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

Alternatywą jest napisać ogólny sposób, który robi wszystko, co chcesz w sposób statycznie wpisany, i nazywają że z refleksji zamiast. To może być przydatny sposób upewnienia się, że potrzebujesz tylko jednego fragmentu refleksji.

+0

Miło, nie myślałem o refleksji z jakiegoś powodu. Będę o tym miał na myśli, gdy ponownie zajmuję się dynamicznym \ generics. –

Powiązane problemy