2009-08-11 37 views
6

điều này có khả thi không? (Tôi không có so với năm 2010, vì vậy tôi không thể thử nó bản thân mình, xin lỗi)IList sử dụng hiệp phương sai và contravariance trong C#, điều này có khả thi không?

public interface IComplexList<out TOutput, in TInput> where TOutput : TInput 
{ 
    public IEnumerator<TOutput> GetEnumerator(); 
    public void Add(TInput item); 
} 

public interface IList<T> : IComplexList<T, T> 
{ 
} 

Nếu tôi làm cho nó đúng, bạn có thể sử dụng để thực thi hiệp phương sai và contravariance trong cùng một giao diện.

Trả lời

5

Không, bạn không thể. Trong ví dụ của bạn IList<T> là bất biến. IList<T> sẽ yêu cầu khai báo in/out để trở thành biến thể/contravariant. Nó không thể làm điều đó chỉ bằng cách thừa hưởng một số giao diện đó là biến đổi.

8

Vâng, câu hỏi của bạn hơi khó hiểu do loại IList<T> hiện tại. Tuy nhiên, sau không biên dịch:

public interface IComplexList<out TOutput, in TInput> where TOutput : TInput 
{ 
    IEnumerator<TOutput> GetEnumerator(); 
    void Add(TInput item); 
} 

public interface ISimpleList<T> : IComplexList<T, T> 
{ 
} 

Bạn thậm chí có thể thay đổi nó để mở rộng IEnumerable<TOutput>:

public interface IComplexList<out TOutput, in TInput> 
    : IEnumerable<TOutput> 
    where TOutput : TInput 
{   
    void Add(TInput item); 
} 

public interface ISimpleList<T> : IComplexList<T, T> 
{ 
} 

Các indexer là khó khăn, bởi vì bạn muốn loại khác nhau có liên quan. Bạn có thể làm:

TOutput Get(int index); 
void Set(int index, TInput item); 

và sau đó đặt indexer vào ISimpleList<T> thay vì tất nhiên ...

Đó không cho phép bạn sử dụng ISimpleList<T> variantly mặc dù, bởi vì bạn đã cơ bản buộc TInput = TOutput.

Một phương pháp khác là để tách ra các đầu vào từ đầu ra:

public interface IReadableList<out T> : IEnumerable<T> 
{ 
    T Get(int index); 
} 

public interface IWritableList<in T> 
{ 
    void Add(T item); 
    void Set(int index, T item); 
} 

public interface IMyList<T> : IReadableList<T>, IWritableList<T> {} 

Sau đó, bạn có thể viết:

public void Foo(IWritableList<string> x) { ... } 

IMyList<object> objects = new MyList<object>(); 
Foo(objects); 

và ngược lại cho IReadableList. Nói cách khác, bạn cho phép phương sai cho mỗi bên riêng lẻ, nhưng bạn không bao giờ có được phương sai cho hai bên với nhau.

+0

Nó chắc chắn không biên dịch nhưng nó sẽ không được đồng/contra-biến thể. Không thể sử dụng 'ISimpleList ' làm 'ISimpleList '. –

+0

Cảm ơn bạn đã cố gắng –

+0

Tôi sẽ cập nhật câu trả lời của mình để cụ thể hơn - xin lỗi, vẫn đang suy nghĩ tất cả điều này thông qua. –

0

Nếu việc triển khai thuộc tính đọc cũng được xem là thực hiện thuộc tính chỉ đọc, người ta có thể thêm một dạng hữu ích của hiệp phương sai và đối nghịch bằng cách có IList (của T) lấy từ IReadableList (của Out T)) và IAddableList (trong T). Miễn là các giao diện đó chỉ bao gồm các thành viên có mặt trong IList (Of T) trước khi chúng được xác định, mã thực hiện IList (Of T) sẽ tự động triển khai các thành viên khác. Thật không may, đối với IReadableList là covariant, nó sẽ phải có một thuộc tính chỉ mục chỉ đọc; việc thực thi thuộc tính đọc-ghi trong IList không thể thay thế được. Có IList (Of T) kế thừa từ một IReadableList có thể sử dụng (Of ​​Out T) do đó sẽ phá vỡ tất cả các hiện thực của IList (Of T).

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