Рассмотрите, у меня есть следующие 3 класса / интерфейсы:
class MyClass<T> { }
interface IMyInterface { }
class Derived : IMyInterface { }
И я хочу смочь бросить a MyClass<Derived>
в a MyClass<IMyInterface>
или виза-versa:
MyClass<Derived> a = new MyClass<Derived>();
MyClass<IMyInterface> b = (MyClass<IMyInterface>)a;
Но я получаю ошибки компилятора, если я пробую:
Cannot convert type 'MyClass<Derived>' to 'MyClass<IMyInterface>'
Я уверен, что существует очень серьезное основание, почему я не могу сделать этого, но я не могу думать о том.
Что касается того, почему я хочу сделать это - сценарий, который я воображаю, тот, посредством чего Вы идеально хотите работать с экземпляром MyClass<Derived>
для ухода от большого количества противных бросков однако необходимо передать экземпляр интерфейсу, который принимает MyClass<IMyInterface>
.
Таким образом, мой вопрос является двукратным:
MyClass<Derived>
в то время как все еще способность бросить это в a MyClass<IMyInterface>
?Это не работает, поскольку C # поддерживает ковариацию только для параметров типа интерфейсов и делегатов. Если ваш параметр типа существует только в позициях вывода (т.е. вы возвращаете только его экземпляры из своего класса и не принимаете его в качестве аргумента), вы можете создать такой интерфейс:
interface IClass<out T> { }
class MyClass<T> : IClass<T> { }
Что позволит вам сделать это:
IClass<Derived> a = new MyClass<Derived>();
IClass<IMyInterface> b = a;
Честно говоря, это почти все, что вы собираетесь получить, и для этого требуется, чтобы компилятор C # 4 работал.
Причина, по которой вы не можете сделать это в целом, заключается в том, что большинство классов не являются простыми пустыми примерами. У них есть методы:
class MyClass<T>
{
static T _storage;
public void DoSomethingWith(T obj)
{
_storage = obj;
}
}
interface IMyInterface { }
class Derived : IMyInterface { }
MyClass<Derived> a = new MyClass<Derived>();
Теперь a
имеет метод DoSomethingWith
, который принимает Derived
и сохраняет его в статической переменной типа Derived
.
MyClass<IMyInterface> b = (MyClass<IMyInterface>)a;
Если бы это было разрешено, b
теперь, казалось бы, имеет метод DoSomethingWith
, который принимает все , реализующее IMyInterface
, и будет затем попытайтесь внутренне сохранить его в статической переменной типа Derived
, потому что это все еще тот же объект, на который ссылается a
.
Итак, теперь у вас будет переменная типа Derived
, хранящая ... неизвестно что.