2011-01-04 19 views
34

fondamentalmente sto costruendo un modello T4 molto generico e una delle cose che ho bisogno di fare è dire stampa variable.ToString(). Tuttavia, voglio che valuti gli elenchi e li foreach attraverso loro e invece stampa ListItem.ToString() Il mio modello T4 non sa che tipo variable sarà in anticipo, ecco perché questo è così generico.Come verificare se una variabile è un oggetto IEnumerable

Ma il mio codice corrente che viene generato assomiglia a questo:

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

ottengo un errore di compilazione sulla linea marcata per "Utilizzo del tipo generico System.Generic.Collections.IEnumerable richiede un tipo di argomento"

In realtà non mi importa di che tipo sia, voglio solo sapere se è possibile forzare attraverso la variabile. Quale codice dovrei usare invece?

risposta

48

Avete già accettato una risposta, poiché il generico IEnumerable<T> implementa lo IEnumerable non generico su cui è possibile eseguire il cast.

// 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

Sembra che potrebbe essere la risposta migliore in realtà. – Earlz

+0

Ho cambiato la risposta perché ho finito per usare questo metodo, che a mio parere è molto più pulito. – Earlz

+0

Inoltre, per aggirare il bug Mono menzionato di seguito, ho dovuto eseguire il comando 'variable' su' object' prima. – Earlz

16

Se si desidera eseguire il test per il codice non generico IEnumerable, è necessario includere una direttiva using System.Collections nella parte superiore del file di origine.

Se si desidera verificare per un IEnumerable<T> di qualche tipo, allora avrete bisogno di qualcosa di simile a questo, invece:

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

L'ho già utilizzato nella parte superiore del mio file sorgente. – Earlz

+0

@Earlz 'System.Collections.Generic'!= 'System.Collections' - l'errore nel post è indicativo di non trovare il tipo non generico (IEnumerable). –

+0

Heh, ho usato questo e Mono mi ha dato uno schiaffo con 'Codice IL non valido in EViewEngine.TestView: BuildOutput(): IL_0105: castclass 0x1b000002' Hmm è interessante. – Earlz

2

In genere, senza non generico tipo di base/interfaccia, questo richiede GetType e una ricerca ricorsiva attraverso i tipi/interfacce di base.

Tuttavia, che non si applica qui :-) basta usare il non-generic IEnumerable (System.Collections.IEnumerable), da cui il generic IEnumerable (System.Collections.Generic.IEnumerable<T>) eredita.

1

Beh, un po 'semplice, ma ... se hai solo:

using System.Collections.Generic; 

potrebbe essere necessario aggiungere:

using System.Collections; 

Il primo definisce IEnumerable<T> e quest'ultimo definisce IEnumerable.

14

Le altre risposte hanno evidenziato la differenza IEnumerable generica/non generica, ma dovrei anche sottolineare che vorrete testare specificamente per String perché implementa IEnumerable ma dubito che vorrete trattarlo come un raccolta di personaggi.

0

Questa è una vecchia questione, ma ho voluto mostrare un metodo alternativo per determinare se un SomeType è IEnumerable:

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

si può effettivamente verificare la classe di base di qualsiasi tipo generico direttamente.

instance.GetGenericTypeDefinition() == typeof(IEnumerable<>) 
Problemi correlati