Объекта 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).