【发布时间】:2013-08-07 11:55:07
【问题描述】:
我已经为我的存储库创建了这个接口。
public interface IRepository<T, in TKey> where T: class
{
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
IEnumerable<T> FindAll();
T FindSingle(TKey id);
void Create(T entity);
void Delete(T entity);
void Update(T entity);
}
FindSingle 方法接受一个 ID,该 ID 将用于搜索主键。通过使用in,我希望只允许将引用类型作为TKey 传递。出于好奇,我决定创建一个具体类并将其指定为 int,这样我就可以看到异常。
我查了MSDN,它指出这不应该工作
引用类型支持泛型类型参数中的协变和逆变,但值类型不支持它们。
我创建的类是这样的
public class ProjectRepository : IRepository<Project,int>
{
public IEnumerable<Project> Find(Expression<Func<Project, bool>> predicate)
{
throw new NotImplementedException();
}
public IEnumerable<Project> FindAll()
{
throw new NotImplementedException();
}
public Project FindSingle(int id)
{
throw new NotImplementedException();
}
public void Create(Project entity)
{
throw new NotImplementedException();
}
public void Delete(Project entity)
{
throw new NotImplementedException();
}
public void Update(Project entity)
{
throw new NotImplementedException();
}
}
为什么我在将TKey 指定为值类型的构建时没有收到异常?另外,如果我从参数中删除了in,我会丢失什么? MSDN 文档说逆变允许使用派生较少的类型,但通过删除 in 我可以传递任何类型,因为它仍然是通用的。
这可能表明对逆变和协变缺乏了解,但它让我有点困惑。
【问题讨论】:
-
我怀疑编译器没有抱怨,因为
int是sealed,因此永远不会被用于共同或相反的变体使用。 Variance 是关于当 variant 类型的派生被替换为基类型时编译器如何处理泛型类型类的用法。例如。List<Animal> animals = new List<Cat>();是协变的。而((IRepository<Cat>)repo).Update(animal);是逆变的。 -
@KeithPayne:
List<T>是一个类。类不支持协变和逆变,因此该代码无法编译。赋值的目标需要是协变接口。 -
@DanielHilgarth 谢谢丹尼尔。这个例子应该是
IEnumerable<Animal> animals = new List<Cat>();而第二个例子也不是很好。((IUpdateOnlyRepository<Cat>)repo).Update(animal);更好,因为使用普通的旧存储库意味着方法也会返回变体类型。 -
@KeithPayne:正确。
标签: c# .net contravariance