Объекта IList, используя ковариантность и контравариантность в C#, возможно ли это?

возможно ли это? (У меня нет VS. 2010, поэтому я не могу попробовать сам, извините)

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>
{
}

Если я правильно понял, вы можете использовать это для реализации ковариации и контравариации в одном интерфейсе.

3 ответов


Нет, ты не можешь. В вашем примере IList<T> инвариантна. IList<T> потребуется объявить in/out быть ковариантным / контравариантным. Это невозможно сделать, просто унаследовав некоторый интерфейс, который является ковариантным.


Ну, ваш вопрос немного сбивает с толку из-за существующего IList<T> тип. Однако, после тут compile:

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

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

вы даже можете изменить его на extend 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>
{
}

индексатор сложный, потому что вы хотите, чтобы были задействованы разные типы. Вы могли бы сделать:

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

а затем поместите индексатор в ISimpleList<T> вместо конечно...

это не позволяет использовать ISimpleList<T> хотя variantly, потому что вы в основном заставили TInput=TOutput.

альтернативный подход состоит в том, чтобы отделить вход от выхода:

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> {}

затем вы могли бы написать:

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

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

и наоборот IReadableList. Другими словами, вы допускаете дисперсию для каждой стороны отдельно, но никогда не получаете дисперсию для двух сторон вместе.


Если реализация свойства read-write также рассматривалась как реализация свойства только для чтения, можно было бы добавить полезную форму ковариации и контравариации списка, имея IList(of T), производные от IReadableList(of Out T) и IAddableList(of In T). При условии, что эти интерфейсы просто включали члены, которые присутствовали в IList(of T) до того, как они были определены, код, который реализовал IList(of T), автоматически реализовал бы эти другие члены. К сожалению, для IReadableList чтобы быть ковариантным, он должен иметь свойство индексатора только для чтения; реализация свойства read-write в IList не может быть заменена. Наличие IList(of T) наследуется от используемого IReadableList(из T), таким образом, нарушит все реализации IList (of T).