Justin
Justin

Reputation: 86789

Casting generics and the generic type

Consider, I have the following 3 classes / interfaces:

class MyClass<T> { }

interface IMyInterface { }

class Derived : IMyInterface { }

And I want to be able to cast a MyClass<Derived> into a MyClass<IMyInterface> or visa-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'm sure there is a very good reason why I cant do this, but I can't think of one.

As for why I want to do this - The scenario I'm imagining is one whereby you ideally want to work with an instance of MyClass<Derived> in order to avoid lots of nasty casts, however you need to pass your instance to an interface that accepts MyClass<IMyInterface>.

So my question is twofold:

Upvotes: 6

Views: 603

Answers (2)

Daniel Earwicker
Daniel Earwicker

Reputation: 116744

The reason you cannot do this in general 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 method DoSomethingWith that accepts a Derived and stores it in a static variable of type Derived.

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

If that was allowed, b would now appear to have a method DoSomethingWith that accepts anything that implements IMyInterface, and would then internally attempt to store it in a static variable of type Derived, because it's still really the same object referred to by a.

So now you'd have a variable of type Derived storing... who knows what.

Upvotes: 3

Andrew Hare
Andrew Hare

Reputation: 351748

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

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

Which would allow you to do this:

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

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

Upvotes: 5

Related Questions