Подтвердить что ты не робот

Почему для подписи 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()

4b9b3361

Ответ 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" предоставляет вашему методу для работы.