views:

297

answers:

4

I have a class Something that implements ISomething. How can I convert/cast from an IQueryable<Something> to an IQueryable<ISomething>. When I try to cast, I am able to compile, but the result of the cast is always NULL.

Background: The reason I am doing this is because my Something class is a CodeSmith-generated class (PLINQO template) that has table mapping decoration, methods, etc. My ISomething interface is "POCO-style", in that it is dumb and simply mirrors the properties of the Something class. It also exists in it's own namespace. I am doing this so I don't have to reference the assembly that holds the Something class from my service layer. The assembly that holds the Something class will only need to be referenced in my repository layer now.

A: 

Not how -- but rather, why:

Generic Covariance -- this link will help explain:

C# Generic Covariance

Ian P
The explains the answer, not why the answer is needed. And you'd do better linking to Eric Lippert's series on the topic.
Joel Coehoorn
@Joel: Do you have a link to the series, by any chance?
Dan Esparza
There's not one good link I can give for the whole series. I know there's an index on this StackOverflow answer: http://stackoverflow.com/questions/2184551/difference-between-covariance-contra-variance/2556675#2556675
Joel Coehoorn
+5  A: 

You can use LINQ method Cast

 IQueryable<Something> something = ...
 IQueryable<ISomething> casted = something.Cast<ISomething>();
Nagg
+1  A: 

There is an excellent explanation of the Covariance problem you are encountering in the answer to this question.

Nicholas Murray
+9  A: 

To understand what's going on here, it's important to look at this from the perspective of the type system. To the type system, Something and ISomething are two types that have an inheritence-like relationship (implementation is not exactly inheritance, but close). The generic types IQueryable<Something> and IQueryable<ISomething> do not have this relationship. They are two completely different types, and belong to a completely different part of the inheritance tree (the branch that includes IQueryable) than either Something or ISomething.

So when casting from IQuerable<Something> to IQueryable<ISomething>, as far as the type system is concerned you might as well try to cast from IQueryable<double> to IQueryable<IDataRecord>. The result is the same: it doesn't know how to make that conversion, and so the as operator returns null.

One solution to this problem (not the problem itself, as indicated by others) called covariance is implemented in C# 4.0. .Net Type Variance allows the type system to have a limited understanding of the specialization relationship between two different types that specialize the same generic type, so that when casting from one to the other the type can vary (note the root word here).

For code prior to .Net 4, you have to use something like the .Cast<T>() extension method. But this is less ideal, because it forces a real cast operation, where type variance lets the framework use the actual type that's already there.

Joel Coehoorn