IList с использованием ковариации и контравариантности в c #, возможно ли это? - PullRequest
6 голосов
/ 11 августа 2009

это было бы возможно? (У меня нет по сравнению с 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 ]

8 голосов
/ 11 августа 2009

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

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

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

Вы можете даже изменить его на расширение 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> по-другому, потому что вы в основном принудительно указали 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. Другими словами, вы разрешаете дисперсию для каждой стороны в отдельности, но вы никогда не получите дисперсию для обеих сторон вместе.

5 голосов
/ 11 августа 2009

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

0 голосов
/ 23 декабря 2010

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

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