Ich werde versuchen, die Antwort von Anthony Pegram zu klären.
Generischer Typ ist covariant auf irgendeine Art Argument , wenn es Werte des Typs zurückgibt (zB Func<out TResult>
kehrt Instanzen TResult
, IEnumerable<out T>
kehrt Instanzen T
). Das heißt, wenn etwas Instanzen von zurückgibt TDerived
, können Sie auch mit solchen Instanzen arbeiten, als ob sie von wären TBase
.
Der generische Typ ist bei einigen Typargumenten kontravariant, wenn er Werte dieses Typs Action<in TArgument>
akzeptiert (z. B. Instanzen von TArgument
). Das heißt, wenn etwas Instanzen von benötigt TBase
, können Sie auch Instanzen von übergeben TDerived
.
Es erscheint ziemlich logisch, dass generische Typen, die Instanzen eines bestimmten Typs akzeptieren und zurückgeben (es sei denn, sie sind beispielsweise zweimal in der generischen CoolList<TIn, TOut>
Typensignatur definiert), für das entsprechende Typargument weder kovariant noch kontravariant sind. Beispielsweise List
ist in .NET 4 definiert als List<T>
, nicht List<in T>
oder List<out T>
.
Einige Kompatibilitätsgründe haben möglicherweise dazu geführt, dass Microsoft dieses Argument ignoriert und Arrays für ihr Wertetypargument kovariant gemacht hat. Vielleicht haben sie eine Analyse durchgeführt und festgestellt, dass die meisten Leute Arrays nur so verwenden, als wären sie schreibgeschützt (dh sie verwenden nur Array-Initialisierer, um einige Daten in ein Array zu schreiben), und als solche überwiegen die Vorteile die Nachteile, die durch die mögliche Laufzeit verursacht werden Fehler, wenn jemand versucht, beim Schreiben in das Array die Kovarianz zu nutzen. Daher ist es erlaubt, aber nicht ermutigt.
Wie für Ihre ursprüngliche Frage, list.ToArray()
eine neue erstellt LinkLabel[]
mit den Werten aus ursprünglichen Liste kopiert, und, um loszuwerden, (angemessene) Warnung, müssen Sie in übergeben Control[]
zu AddRange
. list.ToArray<Control>()
wird den Job machen: ToArray<TSource>
akzeptiert IEnumerable<TSource>
als Argument und kehrt zurück TSource[]
; List<LinkLabel>
implementiert schreibgeschützt IEnumerable<out LinkLabel>
, was dank der IEnumerable
Kovarianz an die Methode übergeben werden kann, die IEnumerable<Control>
als Argument akzeptiert .
LinkLabel
(Spezialtyp) zuControl
(Basistyp).