Странное поведение универсального типа

#c# #generics

#c# #универсальные

Вопрос:

Пожалуйста, посмотрите на простой код ниже

 public class A{}

  public class B: A{}

  public class G<T> where T : A
  {
    public T GetT()
    {
      return new A();
    }
  }
  

Этот код некорректен — ошибка компилятора «Не удается преобразовать A в возвращаемый тип T».
Но A на самом деле является T. Если я изменю

 return new A(); 
  

Для

  return new A() as T;
  

все в порядке. В чем причина такого поведения?
Заранее спасибо

UPD: в первоначальном вопросе была ошибка. Теперь исправлено

Ответ №1:

Представьте, что произошло бы, если бы вы сделали:

 public class C : A{}

G<C> x = new G();
C c = x.GetT();
  

Вы действительно не хотите, чтобы это возвращало B ссылку…

as Оператор работает, потому что тогда он просто вернет, что null if T не является ни B ни A … но, вероятно, это не действительно то, что вы имели в виду.

Трудно понять, какой курс действий предложить, не зная, что вы пытаетесь сделать.

Ответ №2:

Переработанный ответ, основанный на обновлении

Хотя это A соответствует общему ограничению where T : A , это конкретный тип. Однако GetT() метод вашего универсального класса имеет общий возвращаемый тип T , поэтому вам нужно привести ваш конкретный тип к вашему общему типу, чтобы сделать возвращаемые значения совместимыми.

Старый ответ справедлив для вашего предыдущего случая возврата new B() .


Старый ответ

Ограничение универсального типа гласит, что оно T должно наследоваться от A ; однако в нем не говорится, что T должно быть B (или производное от него), хотя B случается, что оно само наследуется от A и соответствует ограничению.

Таким образом, возвращаемый тип несовместим ( B всегда B , но T не обязательно B ), и вы получаете ошибку.

Комментарии:

1. хорошо, даже если изменение возвращает new B (); для возврата new A ();, я получил ошибку. возвращает новый A () как T; работает нормально

2. @Gopher: A является конкретным, но T универсальным. Поскольку возвращаемый тип является универсальным, то и то, что вы возвращаете, должно быть универсального типа.

3. вот и объяснение. Спасибо!

4. Я нахожу ваш ответ немного запутанным. Я думаю, что если вы скажете, что B не обязательно является T, это прояснит ситуацию.

Ответ №3:

Тот же код, только с измененными именами

 public class Animal{}

public class G<T> where T : Animal
{
     public T GetT()
     {
       return new Animal();
     }
}

Fish fish = new G<Fish>().GetT();
  

Но GetT() возвращает не Fish, а анонимное «Животное». Есть проблема: даже если верно обратное, не все животные являются рыбами. Вы не можете вернуть Animal, если нужна рыба, а не какой-либо другой вид Animal.

Ответ №4:

where T : A означает, что T должен наследовать от A. Следовательно, T может не быть an A , поэтому вы не можете просто вернуть a B , поскольку C также может быть inherit from A , но a B не является C .