IList在c#中使用协方差和逆变,这可能吗?

时间:2009-08-11 08:44:16

标签: c# generics covariance ilist contravariance

这可能吗? (我没有对阵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 个答案:

答案 0 :(得分:8)

嗯,由于现有的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。换句话说,你可以单独允许每一方的差异,但是你永远不会得到双方的差异。

答案 1 :(得分:5)

不,你不能。在您的示例中,IList<T>是不变的。 IList<T>需要声明in / out是协变/逆变的。仅仅通过继承一些协变的接口是不可能做到的。

答案 2 :(得分:0)

如果读写属性的实现也被认为是只读属性的实现,则可以通过使IList(of T)派生自IReadableList(Out T)来添加List协方差和逆变的有用形式和IAddableList(In T)。如果这些接口只包含在IList(Of T)中定义的成员,那么实现IList(Of T)的代码将自动实现其他成员。不幸的是,为了使IReadableList具有协变性,它必须具有只读索引器属性;无法替换IList中读写属性的实现。让IList(Of T)继承可用的IReadableList(Of Out T)会破坏IList(Of T)的所有实现。