协变接口与逆变接口作为成员 属性
Covariant interface with contravariant interface as member property
我有一个接口,它定义了一个 reader 和任何 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();
reader 也被定义为协变的。它应该允许从某处读取派生的 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 的参数(任何 class 派生自 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 接口的一部分。
我有一个接口,它定义了一个 reader 和任何 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();
reader 也被定义为协变的。它应该允许从某处读取派生的 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 的参数(任何 class 派生自 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 接口的一部分。