#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
.