Я постараюсь уточнить ответ Энтони Пеграма.
Универсальный тип является ковариантным для некоторого аргумента типа, когда он возвращает значения указанного типа (например, Func<out TResult>
возвращает экземпляры TResult
, IEnumerable<out T>
возвращает экземпляры T
). То есть, если что-то возвращает экземпляры TDerived
, вы также можете работать с такими экземплярами, как если бы они были TBase
.
Универсальный тип является контравариантным для некоторого аргумента типа, когда он принимает значения указанного типа (например, Action<in TArgument>
принимает экземпляры TArgument
). То есть, если чему-то нужны экземпляры TBase
, вы также можете передать экземпляры TDerived
.
Кажется вполне логичным, что универсальные типы, которые одновременно принимают и возвращают экземпляры некоторого типа (если он не определен дважды в сигнатуре универсального типа, например CoolList<TIn, TOut>
), не являются ковариантными и контравариантными для соответствующего аргумента типа. Например, List
в .NET 4 определено как List<T>
not List<in T>
или List<out T>
.
Некоторые причины совместимости могли заставить Microsoft проигнорировать этот аргумент и сделать массивы ковариантными по аргументу типа значений. Возможно, они провели анализ и обнаружили, что большинство людей используют массивы только так, как если бы они были только для чтения (то есть они используют инициализаторы массива только для записи некоторых данных в массив), и, как таковые, преимущества перевешивают недостатки, вызванные возможной средой выполнения. ошибки, когда кто-то попытается использовать ковариацию при записи в массив. Следовательно, это разрешено, но не поощряется.
Что касается вашего исходного вопроса, list.ToArray()
создается новый LinkLabel[]
со значениями, скопированными из исходного списка, и, чтобы избавиться от (разумного) предупреждения, вам нужно перейти Control[]
к AddRange
. list.ToArray<Control>()
выполнит свою работу: ToArray<TSource>
принимает в IEnumerable<TSource>
качестве аргумента и возвращает TSource[]
; List<LinkLabel>
реализует доступ только для чтения IEnumerable<out LinkLabel>
, который, благодаря IEnumerable
ковариантности, может быть передан методу, принимающему в IEnumerable<Control>
качестве аргумента.
LinkLabel
(специализированный тип) кControl
(базовый тип).