Spróbuję wyjaśnić odpowiedź Anthony'ego Pegrama.
Typ ogólny jest kowariantny dla argumentu typu, gdy zwraca wartości tego typu (np. Func<out TResult>
Zwraca wystąpienia TResult
, IEnumerable<out T>
zwraca wystąpienia T
). Oznacza to, że jeśli coś zwraca wystąpienia programu TDerived
, możesz równie dobrze pracować z takimi wystąpieniami, jakby były TBase
.
Typ ogólny jest kontrawariantny w przypadku niektórych argumentów typu, gdy akceptuje wartości tego typu (np. Action<in TArgument>
Akceptuje wystąpienia TArgument
). Oznacza to, że jeśli coś wymaga instancji TBase
, możesz równie dobrze przejść w instancjach TDerived
.
Wydaje się całkiem logiczne, że typy generyczne, które zarówno akceptują, jak i zwracają instancje pewnego typu (chyba że jest to zdefiniowane dwukrotnie w sygnaturze typu ogólnego, np. CoolList<TIn, TOut>
) Nie są kowariantne ani kontrawariantne w odpowiednim argumencie typu. Na przykład List
jest zdefiniowany w .NET 4 jako List<T>
, nie List<in T>
lub List<out T>
.
Niektóre przyczyny zgodności mogły spowodować, że firma Microsoft zignoruje ten argument i sprawi, że tablice będą kowariantne w ich argumencie typu wartości. Być może przeprowadzili analizę i odkryli, że większość ludzi używa tablic tylko tak, jakby były tylko do odczytu (to znaczy używają inicjatorów tablic tylko do zapisania niektórych danych w tablicy) i jako takie, zalety przeważają nad wadami spowodowanymi przez możliwe środowisko uruchomieniowe błędy, gdy ktoś spróbuje skorzystać z kowariancji podczas zapisu do tablicy. Dlatego jest to dozwolone, ale nie zalecane.
Jeśli chodzi o Twoje oryginalne pytanie, list.ToArray()
tworzy nowe LinkLabel[]
z wartościami skopiowanymi z oryginalnej listy i aby pozbyć się (rozsądnego) ostrzeżenia, musisz przejść Control[]
do AddRange
. list.ToArray<Control>()
wykona zadanie: ToArray<TSource>
przyjmuje IEnumerable<TSource>
jako argument i zwraca TSource[]
; List<LinkLabel>
implementuje tylko do odczytu IEnumerable<out LinkLabel>
, co dzięki IEnumerable
kowariancji mogłoby zostać przekazane do metody akceptującej IEnumerable<Control>
jako swój argument.
LinkLabel
(typ specjalistyczny) doControl
(typ podstawowy).