Кастинг дженериков и универсального типа

Рассмотрите, у меня есть следующие 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>?
6
задан Andrew Hare 20 April 2010 в 00:06
поделиться

2 ответа

Это не работает, поскольку C # поддерживает ковариацию только для параметров типа интерфейсов и делегатов. Если ваш параметр типа существует только в позициях вывода (т.е. вы возвращаете только его экземпляры из своего класса и не принимаете его в качестве аргумента), вы можете создать такой интерфейс:

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

Что позволит вам сделать это:

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

Честно говоря, это почти все, что вы собираетесь получить, и для этого требуется, чтобы компилятор C # 4 работал.

5
ответ дан 16 December 2019 в 21:37
поделиться

Причина, по которой вы не можете сделать это в целом, заключается в том, что большинство классов не являются простыми пустыми примерами. У них есть методы:

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 , хранящая ... неизвестно что.

3
ответ дан 16 December 2019 в 21:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: