我有一个接口,它为任何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的基本前提过时了。
解决方案是删除 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 接口的一部分。