Reputation: 11
X : BaseX
XView : BaseView<X>
XDAO : BaseDAO<X>
MainViewModel<TX, TView, TDAO>
where TX : X
where TView : View<X>
where TDAO : DAO<X>
XMainViewModel : MainViewModel<X, XView, XDAO>
I have an instance of XMainViewModel<X, XView, XDAO>
. I want to cast this to MainViewModel<BaseX, BaseView<X>, BaseDAO<X>>
. Is this possible? It might have covariants involved. I'm not familiar with covariants, and only started using generics not long ago so I'm rather confused here (I also hope I did not make any typos in the question). Any help is appreciated.
Upvotes: 0
Views: 179
Reputation: 660533
Is this possible?
No. Generic covariance and contravariance are supported only on interfaces and delegates constructed with reference types.
I'm rather confused here
It's a confusing topic. One way to think about it is to always be asking yourself "suppose this were legal; what could go wrong?" You say
I have
XMainViewModel<X, XView, XDAO>
. I want to cast this toMainViewModel<BaseX, BaseView<X>, BaseDAO<X>>
Let's look at a simpler example. You have a List<Giraffe>
and you wish to cast it to List<Animal>
. What can go wrong?
List<Giraffe> giraffes = new List<Giraffe>();
giraffes.Add(new Giraffe());
List<Animal> animals = (List<Animal>)giraffes; // This is illegal. What if it were legal?
animals.Add(new Tiger());
Giraffe g = giraffes[1]; // And we just put a Tiger into a variable of type Giraffe.
That's why this is illegal, and why your example would also be illegal. But this is legal:
IEnumerable<Animal> animals = giraffes;
Why is that legal? Because IEnumerable provides no way at all for a tiger to be inserted. The interface has been marked as safe for covariance, and the C# compiler has verified that it is safe, so this conversion is allowed.
I've written lots of SO answers and blog posts and articles on covariance and contravariance, so do some searches if you want to learn more about this feature and why we designed it as we did.
You could make your example legal by (1) make MainViewModel<A, B, C>
into an interface and mark it IMainViewModel<out A, out B, out C>
, and then (2) ensure that no method of the interface takes an A, B or C as a parameter, no property of type A, B or C has a setter, and so on. That is, every usage of A, B and C is an output position, not an input position. That's how the compiler knows that it is safe for covariance.
I also hope I did not make any typos in the question
It's "covariance", not "covariants". "Covariance" is a noun; "covariant" is an adjective.
Upvotes: 6