2012-09-29 12 views
6

chciałbym zrobić coś takiegoJak sprawdzić, czy typ T metody ogólnej jest IEnumerable <> i zapętlić go?

void DoSomething<T>(T param) 
{ 
    if param is IEnumerable<?> 
    { 
     loop param and do stuff 
    } 
} 

nie wiem, co robić w miejscu znaku zapytania. I czy to w ogóle możliwe?

+0

Jeśli 'param' nie jest typu' IEnumerable ', czy chcesz coś zrobić? Jeśli nie, to dlaczego ograniczyć 'T' do typu' IEnumerable 'z [where] (http://msdn.microsoft.com/en-us/library/bb384067.aspx)? –

+0

Możliwe odpowiedzi tutaj: http://stackoverflow.com/questions/1846671/determine-if-collection-is-of-type-ienumerablet –

+0

odpowiedzi na przepełnienie stosu postu [kliknij tutaj] [1] [1]: http://stackoverflow.com/questions/906499/getting-type-t-from-ienumerablet –

Odpowiedz

7

Co szukasz jest:

if (T is IEnumerable) { .. } 

ale jeśli oczekujesz T być IEnumerable cały czas można zrobić:

void DoSomething<T>(T param) where T : IEnumerable 
{ 
    foreach (var t in param) { ... } 
} 

lub sprawdzanie typ wartości wewnątrz IEnumerable :

public void DoSomething<T,U>(T val) where T : IEnumerable<U> 
{ 
    foreach (U a in val) 
    { 
    } 
} 

Nie martwiąc się, aby sprawdzić to sam, kompilator zrobi to za Ciebie, co jest jedną z miłych rzeczy o statyczny system typu i kompilator :)

+0

Myślę, że on rzeczywiście próbuje sprawdzić, że IEnumerable określonego typu, a nie tylko ogólne IEnumerable. link w komentarzu pod pytaniem obsługuje ten scenariusz –

+0

Dobrze. Uzupełniam odpowiedź tym scenariuszem, dziękuję. –

+0

Dzięki za dobrą odpowiedź. Problem polega na tym, że nie oczekuję, że T będzie cały czas niezliczony. W rzeczywistości mam już metodę "void ProcessList (IEnumerable list)" i chcę ją ponownie użyć w 'DoSomething()' jeśli argument jest IEnumerable. – tranmq

0

Istnieje kilka sposobów:

void DoSomething<T>(T param) 
{ 
    if (param is IEnumerable) 
    { 
     foreach (var item in (IEnumerable)param) 
     { 
      // Do something 
     } 
    } 
} 

void DoSomething<T>(T param) 
{ 
    if (param is IEnumerable<string>) 
    { 
     foreach (var item in (IEnumerable<string>)param) 
     { 
      // Do something 
     } 
    } 
} 

void DoSomething<T,TItem>(T param) 
{ 
    if (param is IEnumerable<TItem>) 
    { 
     foreach (var item in (IEnumerable<TItem>)param) 
     { 
      // Do something 
     } 
    } 
} 
+0

Najlepszą praktyką jest użycie 'as' zamiast' is'-plus-direct-cast, ponieważ 'as' czy kosztowny test typu run-time wykonuje się tylko raz, a is-plus-direct-cast wykonuje to dwukrotnie. – phoog

0

Trzeba sprawdzić otwarty ogólny typ każdego interfejsu, który implementuje klasy, takie jak tak:

bool implements = typeof(T).GetInterfaces().Where(t => t.IsGenericType && 
    t.GetGenericTypeDefinition() == typeof(IEnumerable<>)).Any(); 

to pozwoli Ci określić, czy dany typ implementuje IEnumerable<T> bez faktycznie wiedząc, co typ T jest. Pamiętaj, że ten typ może wielokrotnie implementować IEnumerable<T>.

Jeśli chcesz po prostu sekwencji typów, które są parametrami typu dla IEnumerable<T>, możesz zmienić powyższe zapytanie na;

IEnumerable<Type> types = typeof(T).GetInterfaces(). 
    Where(t => t.IsGenericType && 
     t.GetGenericTypeDefinition() == typeof(IEnumerable<>)). 
    Select(t => t.GetGenericArguments()[0]); 
+0

Typ implementujący 'IEnumerable ' wiele razy jest rzeczywiście przerażającym typem. – phoog

Powiązane problemy