具有逆变接口的协变接口作为成员属性

时间:2017-07-28 16:55:14

标签: c# generics interface covariance contravariance

我有一个界面,可以为任何IFoo定义一个阅读器和一个编写器。

public interface IFoobarStore<out E>
 where E : class, IFoobar
{
    IFoobarReader<E> GetReader();
    IFoobarWriter<E> GetWriter();
}

IFoobarStore是协变的。 IFoobarStore与任何派生的IFoo交互。因此,任何派生的IFoo都应该可以赋予更多派生的IFoo类型参数。

// DerivedFoobityStore.cs
public sealed class DerivedFoobityStore
 : IFoobarStore<MyFoobity>
{
    // implementation follows
}

如果IFoobarStore被定义为IFoobarStore<E>而不是IFoobarStore<out E>的变体,则以下将产生编译器错误CS0266。

IFoobarStore<IFoo> myGenericStore = new DerivedFoobityStore();

读者也被定义为协变。它应该允许从某个地方读取派生的IFoo对象。

using System.Collections.Generic;
public interface IFoobarReader<out E>
 where E : class, IFoo
{
    IEnumerable<E> GetAll();
    IEnumerable<E> GetBy(params object[] vars);
    E GetSingle(object uniqueIdentifier);
}

IFoobarWriter在任何IFoo上公开用于标准CRUD操作的成员。

public interface IFoobarWriter<in E>
 where E : class, IFoo
{
    void Add(E foo);
    int Delete(E foo);
    E Update(E foo);
}

由于每个操作都有一个E类型的参数(任何来自IFoo的类),因此必须将IFoobarWriter标记为逆变。

编译代码时,我收到此错误:

Invalid variance: The type parameter 'E' must be contravariantly valid on 'IFoobarStore<E>.GetWriter()'. 'E' is covariant.

如何才能更好地重构此代码以便成功编译?

目前我通过重构IFoobarWriter来处理对象而不是IFoo。

public interface IFoobarWriter<out E>
 where E : class, IFoo
{
    void Add(object foo);
    int Delete(object foo);
    object Update(object foo);
}

这使得IFoobarWriter的基本前提过时了。

1 个答案:

答案 0 :(得分:0)

解决方案是删除E作为IFoobarWriter实例成员方法的可接受参数。

public interface IFoobarWriter<out E>
 where E : class, IFoo
{
    void Add(IFoo foo);
    int Delete(IFoo foo);
    object Update(IFoo foo);
}

通过添加,删除和更新接受IFoo,他们可以有效地限制他们可以处理的类型(而不是将参数设置为object),以满足某些业务需求。

使IFoobarWriter的类型参数E保持协变,使其保持IFoobarStore接口的一部分。