2013-02-22 23 views
8

Mogę implicitly rzucić int do IComparable. Mogę również rzucić listę lub tablicę do IEnumerable.Lista <int> do IEnumerable <IComparable>

Ale dlaczego nie mogę niejawnie rzucić listy do IEnumerable?

Testowałem to w środowisku .net framework 4.5 i Visual Studio 2012 Ultimate.

kod do testu:

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?) 

Odpowiedz

12

Generic wariancji nie stosuje się do typów wartości, w zasadzie. Więc podczas może

trzeba by box każdą wartość:

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

więc gdy jest to ważne, ponieważ string jest typ referencyjny:

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

... równowartości nie działa dla List<int>, a musisz pudełko, jak idziesz.

+0

Po przeczytaniu poprzez swoją odpowiedź i porównano z kopalni (a następnie przetestowany w kodzie), zdaję sobie sprawę, że moja jest w tym przypadku błędna, ponieważ zajmuje się konwersjami z Listy -> Lista zamiast Lista -> IEnumerable, ale jestem zdziwiony, dlaczego to robi różnicę. Możesz wytłumaczyć? –

+0

@JonEgerton: Podejrzewam, że wstawiłeś argumenty typu ogólnego w tym komentarzu, ale nie widzę ich. Spróbuj ponownie, z backtickami wokół bitów związanych z kodem. –

+1

@JonEgerton: Okay, czytając twoją odpowiedź, potem twój komentarz znowu ... - to dlatego, że 'List ' nie jest kowariantny w 'T', ale' IEnuemrable 'jest (od .NET 4). Klasy nigdy nie mogą być wariantem. Wyszukaj "ogólną wariancję" w witrynie MSDN, aby uzyskać więcej informacji :) –

2

To powszechne zamieszanie z listami leków generycznych, ale w zasadzie, jeśli generalizować go większy sens:

rozważyć tę konfigurację:

public interface IA{ 
} 

public class A : IA{ 
} 

var listA = new List<A>(); 

Poniższa linia nie będzie działać:

List<IA> listI = ListA; 

Zasadniczo jest tak, ponieważ, mimo że A : IA, List<I> does not : List<A> - są to całkowicie oddzielne typy.

Można zrobić do obsady dość łatwo, choć stosując metodę Cast:

listI = ListA.Cast<IA>(); 

Więc w twoim przypadku można zrobić

test3 = t2.Cast<IComparable>(); 
Powiązane problemy