2010-07-27 3 views
5

Ich entdeckte, dass eine Liste von konkreten Objekten nicht zu einer Liste von Schnittstellenobjekt hinzugefügt werden kann.Liste <IJob> .AddRange (Liste <Job>) funktioniert nicht

public static void AddJob(List<IJob> masterJobs, List<Job> jobs) 
{ 
    masterJobs.AddRange(jobs); //fail to compile 
} 

Stattdessen muss man den folgenden Code verwenden:

public static void AddJob(List<IJob> masterJobs, List<Job> jobs) 
{ 
    masterJobs.AddRange(jobs.Cast<IJob>()); 
} 

Was ist die rationale dahinter?

+5

Skeet + Kovarianz/Kontravarianz in drei ... zwei ... eins ... – Will

+0

Funktioniert, wenn Sie in der Lage sind, C# 4.0 zu verwenden –

+1

Ich gehe davon aus, dass der '// nicht Kompilieren' Kommentar in das zweite Beispiel ist von der ersten übrig? Oder kann das auch nicht kompiliert werden? –

Antwort

10

Lasse hat recht, warum das in C# 3 nicht funktioniert - es gibt keine Konvertierung von List<IJob> zu List<Job>.

In C# 4 wird es funktionieren, nicht weil die Liste kovariant ist, sondern weil IEnumerable<T> kovariant ist. Also mit anderen Worten, würde der Code effektiv sein:

public static void AddJob(List<IJob> masterJobs, List<Job> jobs) 
{ 
    IEnumerable<IJob> jobsTmp = jobs; // This is the covariance working 
    masterJobs.AddRange(jobs); // This is now fine 
} 

jobs implementiert IEnumerable<Job>, so gibt es eine Referenz Umstellung auf IEnumerable<IJob> durch Kovarianz, so dass es alles funktioniert gut. Der Aufruf von Cast<T> führt in Ihrer C# 3-Problemumgehung einen ähnlichen Job aus - Sie verwenden ihn, um ihn in eine IEnumerable<IJob> zu konvertieren.

Wenn Sie mehr über generische Varianz wollen, gibt es eine video of my NDC 2010 talk zur Verfügung, oder lesen Eric Lippert series of blog posts darauf.

+0

Also, lassen Sie mich das klarstellen ... sie verwendeten "in" und "out", um Kontra/Kovarianz zu bezeichnen, weil es im Wesentlichen beschreibt, dass die Klasse * nur * eine Instanz des generischen Typs "einnimmt" (dh eine Methode) Argument) oder wenn die Klasse * nur * eine Instanz der Klasse "ausgibt" (dh Rückgabewert einer Methode)? IEnumerable nimmt keine T auf, also ist es sicher, die Klasse als zu markieren, und daher ist der generische Typ kovariant? IList beide nimmt in T und geht aus T, was es invariant macht? – Will

+0

@Will: Ja, das stimmt genau. Weitere Informationen finden Sie in der Blog-Post-Reihe von Eric Lippert über Varianz. Ich bearbeite meinen Beitrag, um ihn zu verlinken. –

+0

Von George, ich denke, ich habe es! Ich denke, ich habe es! (Stichwort Musiknummer) – Will

8

Der Grund ist, dass ein List<IJob> kein List<Job> ist, obwohl ein JobIJob implementiert.

Dies ist Co- oder contra-Varianz (. Ich erinnere mich noch nie, was was ist)

Das Denken geht in etwa so:

Der Compiler kann nicht garantieren, dass AddRange liest nur Dinge aus dem Parameter es ist gegeben, und so kann es nicht garantieren, dass dies sicher ist, und daher kompiliert es nicht.

Zum Beispiel für alle Compiler weiß, AddRange könnte ein anderes Objekt in den jobs Parameter hinzuzufügen, dass implementiert IJob (weil AddRange IJob Sammlungen erwartet), ist aber nicht Job, was was ist jobs zu erwarten, und damit das würde nicht sicher sein.

In C# 4.0 gibt es einige Unterstützung für die Handhabung, aber ich bin mir nicht sicher, es würde Ihren speziellen Fall behandeln, da die Unterstützung auf der Schnittstellenebene und nicht auf der Methodenebene angegeben werden muss.

Mit anderen Worten, Sie müssten auf dem Interface-Typ angeben, dass alles, was zu T in Beziehung steht, nur in die Sammlung geht, niemals daraus, und dann würde der Compiler dies ermöglichen. Eine Sammlung, von der Sie nicht lesen können, wäre jedoch ziemlich sinnlos.

+1

"out" ist Kovarianz und "in" ist Kontravarianz; es ist jetzt "IList " und so ist kovariant. (und ich irre mich darin, siehe unten) – Will

+0

Ooh, nett, glaube nicht, ich habe so kurz eine Zusammenfassung der beiden vorher gesehen, danke! –

+0

Dieser Kerl geht ins Detail über Kovarianz und Kontravarianz Generika-Unterstützung in 4.0: http://www.buunguyen.net/blog/new-features-of-csharp-4.html – Will

Verwandte Themen