我将尝试澄清Anthony Pegram的答案。
当泛型类型返回该类型的值(例如,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
(基本类型)。