Почему для подписи Generic класса требуется указать new(), если тип T нуждается в создании экземпляра?
Я пишу класс Generic следующим образом.
public class Foo<T> :
where T : Bar, new()
{
public void MethodInFoo()
{
T _t = new T();
}
}
Как вы можете видеть, объект _t
типа T создается во время выполнения. Для поддержки создания типичного типа T язык заставляет меня помещать new() в подпись класса. Я бы согласился на это, если Bar является абстрактным классом, но зачем это нужно, если стандартный стандартный класс Bar с открытым конструктором без параметров.
Компилятор запрашивает следующее сообщение, если new() не найден.
Невозможно создать экземпляр типа переменной 'T', потому что у него нет ограничения new()
Ответы
Ответ 1
Поскольку обычно нет предположения, что параметр шаблона должен быть [не абстрактный и] конструктивным [через открытый конструктор без параметров], чтобы тип соответствовал определению параметра шаблона.
Пока вы не добавите ограничение :new()
в шаблон:
- Компилятор не позволит вам создать
T
- Компилятор позволит вам сопоставлять
T
с абстрактными типами или типами без открытого конструктора без параметров
бит :Bar
является ортогональным и означает:
- Не позволяйте людям сопоставлять типы, которые не получены из [или есть]
Bar
- Позвольте мне нарисовать
T
до Bar
или типы, полученные из Bar
внутри тела
- позвольте мне вызвать общедоступные и внутренние методы
Bar
на T
Ответ 2
Просто потому, что класс Bar
определяет конструктор без параметров, не означает, что все, что есть Bar
, сделает это - может быть класс, который наследует от Bar
, но скрывает параметр-less конструктор. Такой класс встретил бы ограничение Bar
, но верно нарушил бы ограничение new()
.
(Обратите внимание, что если вы сделаете Bar
sealed
, чтобы избежать этой возможности, вы можете (по понятным причинам) больше не использовать его в качестве общего ограничения) - попытка редактирования создает ошибку CS0701 компилятора.
Ответ 3
Возможно, потому что, если вы не включаете ограничение new()
, тогда T
может быть законным подклассом Bar
без конструктора по умолчанию (т.е. public и без параметров), и в этом случае оператор new T()
внутри метод будет недействительным.
- Только с
Bar
в качестве ограничения T
может быть Bar
или любой производной от Bar
с конструктором по умолчанию или без него.
- Только с
new()
как ограничение, T
может быть любым типом с конструктором по умолчанию.
- С
Bar
и new()
в качестве ограничений T
должен быть Bar
или подклассом Bar
и должен также иметь конструктор по умолчанию.
Ответ 4
Поскольку подклассы Bar могут не иметь конструктора no-arg.
where T : Bar
указывает Bar или подкласс Bar. Если вам просто нужен экземпляр Bar, вы не будете использовать generics. Существует множество экземпляров (например, Object и String), где суперкласс имеет конструктор no-arg, а подкласс - нет.
Ответ 5
Хотя Bar
может быть конкретным, производный класс T
может сам быть абстрактным или иметь конструктор по умолчанию.
Ответ 6
Вероятно, вы можете использовать конструктор Bar:
T _t = new Bar();
без ограничения new()
. Однако вы использовали конструктор T
, и компилятор не может и не предполагает, что построение типа, связанного с T, возможно до тех пор, пока вы не добавите ограничение new().
Ответ 7
Для тех, кто не уверен, помните, что вы можете использовать
where T : IDeviceCommand
потребовать, чтобы T реализовал некоторый интерфейс как минимальное контрактное требование. Вы можете высказать свое мнение выше: "Вы можете позвонить мне, если поставляемый тип" T "как минимум, реализует интерфейс IDeviceCommand". Это, конечно, позволяет сделать ряд (правильных) предположений о том, какие средства, которые "T" предоставляет вашему методу для работы.