Обобщения: что такое ограничение 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 в объявлении параметра типа». Я могу только предположить, что это связано с дженериками. Кто-нибудь знает, что происходит и как я могу заставить этот конструктор работать?


person Mason Wheeler    schedule 20.12.2008    source источник


Ответы (2)


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

<T: constructor>

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

<T: TBaseDatafile, constructor>
person Konrad Rudolph    schedule 20.12.2008
comment
Бах. В этом случае компилятор знает, что TBaseDataFile имеет виртуальный конструктор, не принимающий параметров. - person Mason Wheeler; 21.12.2008
comment
@Mason: Я не могу говорить за Delphi, и в целом вы правы в том, что компилятор мог бы узнать, если бы он просто посмотрел в нужном месте. Однако это работает не так, чтобы сделать код более явным. C++ — это другая история: в сравнимых случаях он не требует таких ограничений. - person Konrad Rudolph; 22.12.2008
comment
@Konrad: Точно, хороший компилятор, такой как FPC 3.1.1, не нуждается в таких ограничениях, там это работает нормально. Судя по всему, компилятор Delphi не очень хорош, и это одна из причин, по которой он почти мертв. - person tk_; 22.10.2016

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

Вам не нужно ограничение конструктора, и вы также можете сделать это для объекта с параметрами, используя 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;
person Atle S    schedule 04.09.2011
comment
На самом деле проще всего написать TBaseDatafile(T).Create - person David Heffernan; 05.09.2011