Спробую уточнити відповідь Ентоні Пеграма.
Загальний тип є коваріантним для аргументу типу, коли він повертає значення зазначеного типу (наприклад, Func<out TResult>
повертає екземпляри TResult
, IEnumerable<out T>
повертає екземпляри T
). Тобто, якщо щось повертає екземпляри TDerived
, ви також можете працювати з такими екземплярами, як ніби вони були TBase
.
Загальний тип є протилежним для аргументу деяких типів, коли він приймає значення вказаного типу (наприклад, Action<in TArgument>
приймає екземпляри TArgument
). Тобто, якщо щось потребує екземплярів TBase
, ви можете також передавати їх в екземпляри TDerived
.
Здається цілком логічним, що загальні типи, які приймають і повертають екземпляри якогось типу (якщо вони не визначені двічі в підписі загального типу, наприклад CoolList<TIn, TOut>
), не є коваріантними та не противаріантними у відповідному аргументі типу. Наприклад, List
визначено в .NET 4 як List<T>
, не 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
(базового типу).