2010-03-22 38 views
5

Say, ví dụ, tôi có một lớp:Tại sao một chức năng mất IEnumerable <interface> không chấp nhận IEnumerable <class>?

public class MyFoo : IMyBar 
{ 
    ... 
} 

Sau đó, tôi muốn sử dụng đoạn mã sau:

List<MyFoo> classList = new List<MyFoo>(); 
classList.Add(new MyFoo(1)); 
classList.Add(new MyFoo(2)); 
classList.Add(new MyFoo(3)); 

List<IMyBar> interfaceList = new List<IMyBar>(classList); 

Nhưng điều này tạo ra lỗi:

`Argument '1': cannot convert from 'IEnumerable<MyFoo>' to 'IEnumerable<IMyBar>' 

Tại sao điều này? Kể từ khi MyFoo thực hiện IMyBar, người ta sẽ mong đợi rằng một IEnumerable của MyFoo có thể được coi như một IEnumerable của IMyBar. Một ví dụ thực tế trần tục đang sản xuất một danh sách những chiếc xe, và sau đó được cho biết rằng nó không phải là một danh sách các loại xe.

Nó chỉ là một ít phiền toái, nhưng nếu ai cũng có thể làm sáng tỏ điều này, tôi sẽ có nhiều nghĩa vụ.

+1

Câu trả lời bạn sau cũng được đề cập trong câu hỏi này: http://stackoverflow.com/questions/2346763/any-simple-way-to- giải thích-tại sao-i-không-do-listanimal-động vật-new-arraylistdo/2346857 # 2346857 –

+0

Vâng cảm ơn - Tôi thấy rằng trong danh sách 'liên quan' một khi tôi đã đăng câu hỏi, nhưng nó không xuất hiện trong khi Tôi đã viết nó ... –

Trả lời

14

Điều này sẽ hoạt động trong C# 4.0! Những gì bạn đang nói đến được gọi là hiệp phương sai chung.

Trong khi đó bạn có thể sử dụng Cast extension method:

List<IMyBar> interfaceList = new List<IMyBar>(classList.Cast<IMyBar>()); 
+1

Ok, rực rỡ, nhưng nó không thực sự có vẻ giống như khoa học tên lửa - có lý do cụ thể nào tại sao nó không được hỗ trợ trước đó không? –

+0

@Matt: Nó không phải là khoa học tên lửa nhưng giống như bất kỳ tính năng nào, cần thời gian và tiền bạc để thực hiện và có một số tính năng tuyệt vời với ưu tiên cao hơn mà chúng đã triển khai sớm hơn (ví dụ: LINQ thực sự tốt, phải không?). Bạn sẽ phải cắt giảm một số tính năng tuyệt vời để gửi sản phẩm kịp thời. - Một điều cần lưu ý về tính năng cụ thể này là nó yêu cầu sự hỗ trợ từ CLR và CLR bên dưới không hỗ trợ nó. Hỗ trợ được thêm vào trong CLR 4.0. –

+0

Cảm ơn - rất hữu ích ... :) –

3

này được hỗ trợ trong .NET 4.0 nhưng không phải trước đó.

http://msdn.microsoft.com/en-us/library/dd799517%28VS.100%29.aspx

+1

Về mặt kỹ thuật nó được hỗ trợ trong .Net qua IL từ 2.0 nhưng nó chỉ được hỗ trợ trong C# và VB.Net trong 4.0 – JaredPar

+0

@ JaredPar: Thật sao? CLR 2.0 có hỗ trợ hiệp phương sai chung trong * có thể xác minh * IL không? –

+0

@Mehrdad, Vâng tôi tin như vậy. Đã hơn 1 năm kể từ khi tôi thảo luận với Lucian nhưng hồi ức hiện tại của tôi là CLR hỗ trợ đồng/contravariance kể từ 2.0 và 4.0 là tất cả trong các trình biên dịch (có thể sửa lỗi hoặc hai trong CLR). – JaredPar

3

Để làm rõ, lý do nó không hoạt động tại là vì IEnumerable<MyClass> không kế thừa từ IEnumerable<MyBar>. Tôi sẽ nói lại điều đó: số đếm của kiểu dẫn xuất không thừa kế từ kiểu đếm được của kiểu cơ sở. Thay vào đó, cả hai loại đều là loại chung loại IEnumerable<T>. Trong Net 3.5 và thấp hơn, chúng không có mối quan hệ nào khác ngoài chuyên môn hóa (không phải là thừa kế) và nếu không có hai loại hoàn toàn khác nhau trong hệ thống kiểu.

.Net 4.0 sẽ không thay đổi cách các loại này liên quan chút nào. Họ sẽ vẫn là hai loại hoàn toàn khác nhau chỉ liên quan đến thông qua chuyên môn hóa. Những gì nó sẽ làm là cho phép bạn viết các phương thức mà biết về mối quan hệ chuyên môn hóa và trong một số trường hợp cho phép bạn thay thế một khi bạn đã viết cái kia.

+1

Để làm rõ đoạn thứ hai của bạn: điểm của phương sai chung là nó thay đổi quan hệ "là gán tương thích với" trên một số kiểu chung nhất định. Đó là quan hệ liên quan; quan hệ thừa kế không thay đổi, như bạn nói. –

+0

Joel, tôi chưa bao giờ nghĩ về phương sai đồng phương/contra theo cách này. Câu trả lời rất hữu ích, +1 từ tôi. – SolutionYogi

1

Nếu bạn muốn truyền giữa các IEnumerables (như bạn đã viết trong dòng tiêu đề câu hỏi của bạn) và không nằm giữa Danh sách (như bạn đã viết trong câu hỏi của mình), bạn có thể đợi tính năng hiệp phương sai C# 4.0. Trước ngày đó, bạn có thể sử dụng các phương pháp mở rộng. Nhưng tôi sẽ không sử dụng các câu trả lời khác Cast extension method, nhưng viết phương pháp riêng của tôi, có thể chỉ được sử dụng cho đúc hiệp phương sai trong IEnumerable. Khi/Nếu bạn chuyển sang C# 4.0, bạn sẽ dễ dàng tìm thấy tất cả các địa điểm trong mã của bạn, nơi diễn viên sẽ bị dư thừa.

public static class cEnumerableExtensions 
{ 
    public static IEnumerable<TResult> CovarianceConversion<TResult, TSource>(this IEnumerable<TSource> source) 
     where TSource : TResult 
    { 
     foreach (var item in source) 
     { 
      yield return item; 
     } 
    } 
} 

Nút cuối cùng. Dường như có no precompiler constant for the netframework 4.0, nếu không tôi sẽ thêm

#if DOTNET4 
    [Obsolete("You can directly cast in C# 4.0.")] 
    #endif 
Các vấn đề liên quan