5

我有一个工厂函数来返回一个DbSet(Of IItemType). IItemType例如,实际的返回类型将始终是一个实现DbSet(Of CategoryType)

我认为泛型支持协方差,并且这种方法可以正常工作,但是当我尝试运行我的代码时出现异常:

无法转换类型为“System.Data.Entity.DbSet 1[CategoryType]' to type 'System.Data.Entity.DbSet1[IItemType]”的对象。

4

2 回答 2

7

DbSet<T>不能是协变的。首先,这是因为在 C# 中,类不能是协变的……只有接口。其次,因为DbSet<T>同时具有协变和反变方法。

举以下两个例子。

DbSet<CategoryType> set = context.Set<CategoryType>();
IQueryable<IItemType> query = set.Where(x => x.Foo == Bar);

所以我们知道所有CategoryTypes 都是IItemType,所以我们知道这总是可以工作的。

然而反过来试试这个......

DbSet<CategoryType> set = context.Set<CategoryType>();
IItemType newItemType = new ProductType();
set.Add(newItemType);  // Compiler error.

不是所有IItemType的 s 都是CategoryType。因此,如果我们可以强制转换DbSet<CategoryType>DbSet<IItemType>我们会在添加时遇到运行时错误... 因为编译器知道这可能并不总是有效,所以它不会让你进行强制转换。

但是,有些接口DbSet<T>确实允许启用协方差。例如,您可以尝试将其转换IQueryable<IItemType>为。

但是,听起来您正在尝试使用针对接口的查询来查询 DbSet ...尝试以下操作

DbSet<CategoryType> set = context.Set<CategoryType>();
IQueryable<IItemType> cast = set.OfType<IITemType>(); //(or .Cast<>() works too)
IQueryable<IItemType> query = cast.Where(x => x ....);
于 2013-09-30T06:42:31.910 回答
2

看起来它们可能是协变的。但是内存编程和针对查询提供程序的编程之间存在许多差异。

对于实体框架从数据存储实现对象,它需要其确切类型以及从数据库列到类型属性的映射。接口可以表示任何类型,而 EF (还)不能自己选择合适的实现。也许对接口的支持将在未来的版本中提供。

这同样适用于将实体转换为 EF 查询中的接口(我刚刚添加到差异列表中的情况)。

于 2013-09-29T21:43:37.930 回答