IList использует ковариацию и контравариацию в С#, возможно ли это?
-
12-09-2019 - |
Вопрос
возможно ли это?(у меня нет 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).