Casting generation and generic type

Consider that I have the following 3 classes / interfaces:

class MyClass<T> { } interface IMyInterface { } class Derived : IMyInterface { } 

And I want to be able to use MyClass<Derived> in MyClass<IMyInterface> or vice versa:

 MyClass<Derived> a = new MyClass<Derived>(); MyClass<IMyInterface> b = (MyClass<IMyInterface>)a; 

But I get compiler errors if I try:

 Cannot convert type 'MyClass<Derived>' to 'MyClass<IMyInterface>' 

I am sure there is a very good reason why I cannot do this, but I cannot come up with this.

Why do I want to do this? The scenario I present is one in which you ideally want to work with an instance of MyClass<Derived> to avoid a lot of unpleasant throws, however you need to pass your instance an interface that accepts MyClass<IMyInterface> .

So my question is twofold:

  • Why can't I use these two types?
  • Is there a way to preserve the superiority of working with an instance of MyClass<Derived> , although it is still able to pass this to MyClass<IMyInterface> ?
+6
generics casting c # covariance
source share
2 answers

This does not work because C # only supports covariance on parameters like interfaces and delegates. If your type parameter exists only in output positions (i.e. you only return instances of it from your class and do not accept it as an argument), you can create an interface like this:

 interface IClass<out T> { } class MyClass<T> : IClass<T> { } 

This will allow you to do this:

 IClass<Derived> a = new MyClass<Derived>(); IClass<IMyInterface> b = a; 

Honestly, this is about as close as you are, and this requires the C # 4 compiler to work.

+5
source share

The reason you cannot do this at all is because most classes are not simple empty examples. They have methods:

 class MyClass<T> { static T _storage; public void DoSomethingWith(T obj) { _storage = obj; } } interface IMyInterface { } class Derived : IMyInterface { } MyClass<Derived> a = new MyClass<Derived>(); 

Now a has a DoSomethingWith method that takes Derived and stores it in a static variable of type Derived .

 MyClass<IMyInterface> b = (MyClass<IMyInterface>)a; 

If it was allowed, now b will now have a DoSomethingWith method that takes everything that IMyInterface implements, and then internally tries to save it in a static variable of type Derived , because it is still actually the same object referenced by a .

So now you will have a variable like Derived storageing ... who knows what.

+3
source share

All Articles