2017-09-28 14 views
8

Tôi đang học về C# generics và tạo một số mã giả cho mục đích thử nghiệm. Vì vậy, tôi đang thử nghiệm các in Generic Modifier, trong đó xác định rằng các tham số kiểu là contravariant.Sử dụng phép so sánh chung với IList và IEnumerable

Với giao diện dưới đây:

public interface IInterfaceTest<in T> 
{ 
    void Method(T value); 
    void Method(IList<T> values); 
    void Method(IEnumerable<T> values); 
} 

Khi biên dịch, tôi nhận được thông báo lỗi:

[CS1961] đúng không hợp lệ: Các tham số kiểu 'T' phải invariantly hợp lệ trên 'IInterfaceTest.Method (IList)'. 'T' là contravariant.

Lỗi này chỉ liên quan đến dòng void Method(IEnumerable<T> values). Nếu dòng này bị xóa, tất cả đều hoạt động tốt.

Vì vậy, câu hỏi của tôi là: Tại sao tôi có thể sử dụng biến thể chung với IEnumerable nhưng không với IList? Tôi có quên gì không?

Cảm ơn.

+5

'IList ' không phải là, và không thể là, biến thể. – SLaks

+2

@SLaks: Tôi nghĩ OP nhận được điều đó, nhưng tại sao? (cũng sẽ giúp tôi) – Stefan

+6

Vì nó có thể thay đổi. https://stackoverflow.com/a/2033921/34397 – SLaks

Trả lời

4

Câu hỏi tại sao nó không được phép cho IList<T> đã được trả lời trong các ý kiến ​​và liên kết các câu hỏi đã được: IList<T> là bất biến trong T và do đó, một trường hợp bị biến Tkhông thể được sử dụng ở đây nào.

Điều làm tôi bối rối lúc đầu là thực tế rằng Method(IEnumerable<T>) được cho phép tại đây. Điều kỳ lạ là phương pháp được "xoay vòng" khi bạn sử dụng T làm đối số loại cho loại chung khác.

Hãy tưởng tượng điều này.

public interface ITestInterface<in T> 
{ 
    void Method(IEnumerable<T> e); 
    IEnumerable<T> GetMethod(); // illegal 
} 
public class Animal {} 
public class Lion : Animal [} 
public class Gnu : Animal {} 

ITestInterface<Animal> animals; 
ITestInterface<Lion> lions; 
ITestInterface<Gnu> gnus; 

Bây giờ contra-sai của ITestInterface<in T> trong T cho chúng ta biết rằng bạn có thể làm

lions = animals; 

Và khi bạn gọi lions.Method(e), bạn chỉ có thể cung cấp một IEnumerable<Lion>. Vì vậy, mã của Method chỉ có thể liệt kê Lion s, trong đó tất cả Animalsanimals.Method() mong đợi. Mọi thứ đều ổn.

Mặt khác, IEnumerable<T> GetMethod() là bất hợp pháp, bởi vì:

gnus = animals; 

là hợp pháp, và bây giờ gnu.GetMethod() sẽ trả về một IEnumerable<Animal> nơi bạn mong muốn một IEnumerable<Gnu>. Và khi bạn lặp lại, các động vật đáng ngạc nhiên có thể chờ đợi trong chuỗi đó.

+2

Phương sai đối với 'T' là" quay lại "cho _inputs_ có mối quan hệ với' T'. Các đầu ra phải có cùng phương sai đối với 'T'. Ví dụ: 'Action GetMethod()' sẽ hợp lệ vì 'Hành động <-T>' thay đổi với 'T' theo cùng cách với' ITestInterface <-T> '. Khác hơn thế, câu trả lời hay. –

Các vấn đề liên quan