Generics: Что такое «ограничение CONSTRUCTOR»?

Я создал собственный потомок TObjectList, предназначенный для хранения подклассов базового класса объектов. Это выглядит примерно так:

interface
   TMyDataList<T: TBaseDatafile> = class(TObjectList<TBaseDatafile>)
   public
      constructor Create;
      procedure upload(db: TDataSet);
   end;

implementation

constructor TMyDataList<T>.Create;
begin
   inherited Create(true);
   self.Add(T.Create);
end;

Я хочу, чтобы каждый новый список начинался с одного пустого объекта. Это довольно просто, правда? Но компилятору это не нравится. Он говорит:

«Невозможно создать новый экземпляр без ограничения CONSTRUCTOR в объявлении параметра типа» Я могу только предположить, что это что-то связанное с дженериками. Кто-нибудь знает, что происходит и как я могу заставить этот конструктор работать?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
9
0
4 289
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы пытаетесь создать экземпляр T через T.Create. Это не работает, потому что компилятор не знает, что ваш универсальный тип имеет конструктор без параметров (помните: это не требование). Чтобы исправить это, вам нужно создать ограничение конструктора, которое выглядит следующим образом:

<T: constructor>

или, в вашем конкретном случае:

<T: TBaseDatafile, constructor>

Ба. В этом случае компилятор делает знает, что TBaseDataFile имеет виртуальный конструктор, который не принимает параметров.

Mason Wheeler 21.12.2008 17:05

@Mason: Я не могу говорить от имени Delphi, и в целом вы правы, что компилятор мог знает, смотрел ли он просто в нужное место. Однако это просто не так, как это работает, чтобы сделать код более явным. Другое дело C++: он не требует таких ограничений в сопоставимых случаях.

Konrad Rudolph 22.12.2008 20:52

@Konrad: Совершенно верно, хороший компилятор, такой как FPC 3.1.1, не нуждается в таких ограничениях, там это прекрасно работает. Очевидно, компилятор Delphi не очень хорош, и это одна из причин, по которой он почти мертв.

tk_ 22.10.2016 16:17

Просто быстрое обновление старого вопроса ..

Вам не нужно ограничение конструктора, и вы также можете сделать это для объекта с параметрами, используя RTTI, как это (используя RTTI или System.RTTI с XE2)

constructor TMyDataList<T>.Create;
var
  ctx: TRttiContext;
begin
   inherited Create(true);
   self.Add(
     ctx.
     GetType(TClass(T)).
     GetMethod('create').
     Invoke(TClass(T),[]).AsType<T>
   );
end;

Если у вас есть параметры, просто добавьте их вот так

constructor TMyDataList<T>.Create;
var
  ctx: TRttiContext;
begin
   inherited Create(true);
   self.Add(
     ctx.
     GetType(TClass(T)).
     GetMethod('create').
     Invoke(TClass(T),[TValue.From('Test'),TValue.From(42)]).AsType<T>
   );
end;

На самом деле проще всего написать TBaseDatafile(T).Create

David Heffernan 05.09.2011 00:10

Другие вопросы по теме