Tôi sẽ cố gắng làm rõ câu trả lời Anthony Pegram.
Generic loại là hiệp biến trên một số đối số kiểu khi nó trả về giá trị kiểu nói (ví dụ Func<out TResult>
nhuận trường hợp của TResult
, IEnumerable<out T>
nhuận trường hợp của T
). Tức là, nếu một cái gì đó trả về các thể hiện của TDerived
, bạn cũng có thể làm việc với các trường hợp như thể chúng là TBase
.
Loại chung là contravariant trên một số đối số loại khi nó chấp nhận các giá trị của loại đã nói (ví dụ: Action<in TArgument>
chấp nhận các trường hợp TArgument
). Tức là, nếu cần một số phiên bản của TBase
, bạn cũng có thể vượt qua trong các phiên bản TDerived
. Có vẻ như khá hợp lý rằng các loại chung mà cả hai đều chấp nhận và trả về các trường hợp của một số loại (trừ khi được xác định hai lần trong chữ ký loại chung, ví dụ: CoolList<TIn, TOut>
) không phải là biến thể hay contravariant trên đối số kiểu tương ứng. Ví dụ: List
được định nghĩa trong .NET 4 là List<T>
, không phải List<in T>
hoặc List<out T>
.
Một số lý do tương thích có thể đã khiến Microsoft bỏ qua đối số đó và làm cho mảng covariant trên đối số loại giá trị của chúng. Có thể họ đã tiến hành phân tích và thấy rằng hầu hết mọi người chỉ sử dụng mảng như thể họ chỉ đọc (nghĩa là họ chỉ sử dụng công cụ khởi tạo mảng để ghi dữ liệu vào mảng), và, như vậy, lợi thế vượt quá những bất lợi do thời gian chạy có thể xảy ra lỗi khi ai đó cố gắng sử dụng hiệp phương sai khi viết vào mảng. Do đó nó được cho phép nhưng không được khuyến khích.
Đối với câu hỏi ban đầu của bạn, tạo ra một list.ToArray()
mới LinkLabel[]
với các giá trị sao chép từ danh sách ban đầu, và, để thoát khỏi cảnh báo (hợp lý), bạn sẽ cần phải vượt qua trong Control[]
để AddRange
. list.ToArray<Control>()
sẽ thực hiện công việc: ToArray<TSource>
chấp nhận IEnumerable<TSource>
làm đối số và trả về TSource[]
; List<LinkLabel>
thực hiện chỉ đọc IEnumerable<out LinkLabel>
, trong đó, nhờ vào IEnumerable
hiệp phương sai, có thể được chuyển đến phương thức chấp nhận IEnumerable<Control>
làm đối số của nó.
Tôi hiểu sự khác biệt về thời gian chạy/biên dịch như trong ví dụ của bạn nhưng không chuyển đổi từ loại đặc biệt sang loại cơ sở hợp pháp? Hơn nữa tôi đã gõ danh sách và tôi đang đi từ 'LinkLabel' (loại chuyên ngành) để' Control' (loại cơ sở). – TheVillageIdiot
Có, việc chuyển đổi từ một LinkLabel thành Kiểm soát là hợp pháp, nhưng điều đó không giống như những gì đang xảy ra ở đây. Đây là cảnh báo về việc chuyển đổi từ một 'LinkLabel []' thành 'Control []', vẫn còn hợp pháp, nhưng có thể có một vấn đề thời gian chạy. Tất cả những gì đã thay đổi là cách mảng được tham chiếu. Bản thân mảng không bị thay đổi. Xem vấn đề? Mảng vẫn là một mảng của kiểu dẫn xuất. Tham chiếu là thông qua một mảng của kiểu cơ sở.Vì vậy, nó là thời gian biên dịch hợp pháp để gán một phần tử cho nó của kiểu cơ sở. Tuy nhiên, kiểu thời gian chạy sẽ không hỗ trợ nó. –
Trong trường hợp của bạn, tôi không nghĩ rằng đó là một vấn đề, bạn chỉ đơn giản là sử dụng mảng để thêm vào một danh sách các điều khiển. –