我有一个工厂函数来返回一个DbSet(Of IItemType)
. IItemType
例如,实际的返回类型将始终是一个实现DbSet(Of CategoryType)
。
我认为泛型支持协方差,并且这种方法可以正常工作,但是当我尝试运行我的代码时出现异常:
无法转换类型为“System.Data.Entity.DbSet
1[CategoryType]' to type 'System.Data.Entity.DbSet
1[IItemType]”的对象。
我有一个工厂函数来返回一个DbSet(Of IItemType)
. IItemType
例如,实际的返回类型将始终是一个实现DbSet(Of CategoryType)
。
我认为泛型支持协方差,并且这种方法可以正常工作,但是当我尝试运行我的代码时出现异常:
无法转换类型为“System.Data.Entity.DbSet
1[CategoryType]' to type 'System.Data.Entity.DbSet
1[IItemType]”的对象。
DbSet<T>
不能是协变的。首先,这是因为在 C# 中,类不能是协变的……只有接口。其次,因为DbSet<T>
同时具有协变和反变方法。
举以下两个例子。
DbSet<CategoryType> set = context.Set<CategoryType>();
IQueryable<IItemType> query = set.Where(x => x.Foo == Bar);
所以我们知道所有CategoryType
s 都是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 ....);
看起来它们可能是协变的。但是内存编程和针对查询提供程序的编程之间存在许多差异。
对于实体框架从数据存储实现对象,它需要其确切类型以及从数据库列到类型属性的映射。接口可以表示任何类型,而 EF (还)不能自己选择合适的实现。也许对接口的支持将在未来的版本中提供。
这同样适用于将实体转换为 EF 查询中的接口(我刚刚添加到差异列表中的情况)。