Question

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]'.

Was it helpful?

Solution

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 ....);

OTHER TIPS

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).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top