2013-02-22 43 views
8

Posso lanciare implicitamente un int a un IComparable. Posso anche lanciare un elenco o un array su un oggetto IEnumerable.Elenco <int> a IEnumerable <IComparable>

Ma perché non posso trasmettere implicitamente una lista a un oggetto IEnumerable?

L'ho provato con .net framework 4.5 e Visual Studio 2012 Ultimate.

Codice di prova:

IComparable test1; 
int t1 = 5; 
test1 = t1; //OK 

IEnumerable<int> test2; 
List<int> t2 = new List<int>(); 
int[] t3 = new int[] { 5, 6 }; 
test2 = t2; //OK 
test2 = t3; //OK 

TabAlignment[] test; 

IEnumerable<IComparable> test3; 
test3 = t2; //error Cannot implicitly convert type 'System.Collections.Generic.List<int>' to 'System.Collections.Generic.IEnumerable<System.IComparable>'. An explicit conversion exists (are you missing a cast?) 

risposta

12

varianza generico non si applica ai tipi di valore, in fondo. Così, mentre si può

Avresti bisogno di scatola ogni valore:

IEnumerable<IComparable> test3 = t2.Cast<IComparable>(); 

Così, mentre questo è valido perché string è un tipo di riferimento:

List<string> strings = new List<string>(); 
IEnumerable<IComparable> comparables = strings; 

... l'equivalente non funziona per List<int>, ed è necessario boxare mentre si va.

+0

Avendo letto attraverso la tua risposta e confrontato con la mia (e poi testato nel codice), mi rendo conto che il mio è sbagliato in questo caso in quanto riguarda le conversioni da Elenco -> Elenco piuttosto che Elenco -> IEnumerable, ma sono perplesso sul motivo per cui ciò faccia la differenza. Puoi spiegare? –

+0

@JonEgerton: Sospetto che tu abbia inserito argomenti di tipo generico in quel commento, ma non riesco a vederli. Riprovare, con i backtick attorno ai bit relativi al codice. –

+1

@JonEgerton: Ok, leggendo la tua risposta, poi il tuo commento di nuovo ... - perché 'Lista 'non è covariante in' T', ma 'IEnuemrable ' è (a partire da .NET 4). Le classi non possono mai essere una variante. Cerca "varianza generica" ​​su MSDN per maggiori dettagli :) –

2

E 'una confusione comune con gli elenchi dei farmaci generici, ma in fondo se si generalizza si ha più senso:

Considerate questa configurazione:

public interface IA{ 
} 

public class A : IA{ 
} 

var listA = new List<A>(); 

La seguente riga non avrebbe funzionato:

List<IA> listI = ListA; 

Essenzialmente questo perché, anche se A : IA, List<I> does not : List<A> - sono tipi completamente separati.

Si può fare il cast abbastanza facilmente anche se con il metodo Cast:

listI = ListA.Cast<IA>(); 

Quindi nel tuo caso si poteva fare

test3 = t2.Cast<IComparable>();