Why isn't DbSet covariant?

妖精的绣舞 提交于 2019-12-22 07:27:27

问题


I have a factory function to return a DbSet(Of IItemType). The actual return type will always be an implementation IItemType, for example DbSet(Of CategoryType).

I thought covariance is supported in generics and this method would work fine, but I get an exception when I try to run my code:

Unable to cast object of type 'System.Data.Entity.DbSet1[CategoryType]' to type 'System.Data.Entity.DbSet1[IItemType]'.


回答1:


It looks like they could be covariant. But there is a host of differences between in-memory programming and programming against a query provider.

For Entity Framework to materialize an object from the data store it requires its exact type and the mapping from database columns to the type's properties. An interface can represent any type and EF is not (yet) able to pick a suitable implementation itself. Maybe support for interfaces will be featured in future releases.

The same applies to casting entities to an interface in an EF query (a case I just added to my list of differences).




回答2:


DbSet<T> CANNOT be co-variant. Firstly, this is because in C#, classes cannot be co-variant...only interfaces. Secondly because DbSet<T> has both co-variant and contra-variant methods.

Take the following two examples.

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

So we know for a fact that all CategoryTypes are IItemType, so we know this can always work.

However conversely try this...

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

Not all IItemTypes are CategoryType. So if we could cast DbSet<CategoryType> to DbSet<IItemType> we would get run time errors when adding... Since the compiler knows that this might not always work, it won't let you do the casting.

However there are interfaces that DbSet<T> does allow Co-Variance on. You can try casting it to IQueryable<IItemType> for example.

However it sounds like you are trying to query against the DbSet using a query against the interface... try the following

DbSet<CategoryType> set = context.Set<CategoryType>();
IQueryable<IItemType> cast = set.OfType<IITemType>(); //(or .Cast<>() works too)
IQueryable<IItemType> query = cast.Where(x => x ....);


来源:https://stackoverflow.com/questions/19082671/why-isnt-dbset-covariant

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!