问题
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:
- Why can I not cast between these two types?
- Is there any way of keeping the niceness of working with an instance of
MyClass<Derived>
while still being able to cast this into aMyClass<IMyInterface>
?
回答1:
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.
回答2:
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.
来源:https://stackoverflow.com/questions/2671676/casting-generics-and-the-generic-type