2011-01-04 11 views
34

zasadniczo buduję bardzo ogólny szablon T4 i jedną z rzeczy, których potrzebuję, jest wydrukowanie variable.ToString(). Chciałbym jednak, abyśmy ocenili listy i foreach za ich pośrednictwem i zamiast tego wydrukowali ListItem.ToString() Mój szablon T4 nie wie, jaki typ variable będzie przed czasem, dlatego jest tak ogólny.Jak sprawdzić, czy zmienna jest IEnumerable jakiegoś rodzaju

Ale mój aktualny kod, który zostanie wygenerowany wygląda następująco:

if(variable!=null) 
    if(variable is IEnumerable) //error here 
    foreach(var item in variable) 
     Write(item.ToString()); 

otrzymuję błąd kompilatora na zaznaczonej linii dla „Używanie ogólny typ System.Generic.Collections.IEnumerable wymaga jednego argumentu typu”

Nie obchodzi mnie, jaki to jest typ, chcę tylko wiedzieć, czy można się przedostać przez zmienną. Jakiego kodu powinienem użyć?

Odpowiedz

48

Jednak już zaakceptowałeś odpowiedź, ponieważ generyczny IEnumerable<T> implementuje nietypowy IEnumerable, który możesz po prostu rzucić na to.

// Does write handle null? Might need some sanity aswell. 

var enumerable = variable as System.Collections.IEnumerable; 

if (enumerable != null) 
    foreach(var item in enumerable) 
     Write(item); 
else 
    Write(item);  
+0

Wygląda na to, że może to być lepsza odpowiedź. – Earlz

+0

Zmieniłem odpowiedź, ponieważ skończyłem, używając tej metody, która moim zdaniem jest znacznie czystsza. – Earlz

+0

Ponadto, aby ominąć opisany wyżej błąd Mono, musiałem najpierw rzucić 'variable' na' object'. – Earlz

16

Jeśli chcesz przetestować nietypowy kod IEnumerable, musisz dodać dyrektywę using System.Collections u góry pliku źródłowego.

Jeśli chcesz przetestować dla IEnumerable<T> jakiegoś następnie trzeba coś takiego Zamiast:

if (variable != null) 
{ 
    if (variable.GetType().GetInterfaces().Any(
      i => i.IsGenericType && 
      i.GetGenericTypeDefinition() == typeof(IEnumerable<>))) 
    { 
     // foreach... 
    } 
} 
+0

Mam już to za pomocą u góry mojego pliku źródłowego. – Earlz

+0

@Ellz 'System.Collections.Generic'!= 'System.Collections' - błąd w poście wskazuje na to, że nie znajduje się typu ogólnego (IEnumerable). –

+0

Heh, użyłem tego i Mono poklepał mnie z "Nieprawidłowy kod IL w EViewEngine.TestView: BuildOutput(): IL_0105: castclass 0x1b000002' Hmm, to jest interesujące. – Earlz

2

W ogóle, bez nierodzajową typu base/interfejsu, wymaga GetType i rekurencyjne przeglądanie za pomocą typów/interfejsów bazowych.

Jednak, że nie stosuje się tutaj :-) Wystarczy użyć non-generic IEnumerable (System.Collections.IEnumerable), z którego generic IEnumerable (System.Collections.Generic.IEnumerable<T>) dziedziczy.

1

Cóż, nieco proste, ale ... jeśli tylko mają:

using System.Collections.Generic; 

może trzeba dodać:

using System.Collections; 

Dawne definiuje IEnumerable<T> i ostatnie Definiuje IEnumerable.

14

W innych odpowiedziach wskazano na ogólną/nietypową różnicę IEnumerable, ale powinienem również zwrócić uwagę, że będziesz również chciał przetestować String, ponieważ implementuje IEnumerable, ale wątpię, że będziesz chciał traktować to jako kolekcja postaci.

0

To stara sprawa, ale chciałem pokazać alternatywną metodę określania, czy SomeType jest IEnumerable:

var isEnumerable = (typeof(SomeType).Name == "IEnumerable`1"); 
0

Rzeczywiście można przetestować klasę bazową dowolnego typu rodzajowego bezpośrednio.

instance.GetGenericTypeDefinition() == typeof(IEnumerable<>) 
Powiązane problemy