IList использует ковариацию и контравариацию в С#, возможно ли это?

StackOverflow https://stackoverflow.com/questions/1259104

Вопрос

возможно ли это?(у меня нет 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>
{
}

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

Это было полезно?

Решение

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

Другие советы

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top