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





Вы пытаетесь создать экземпляр T через T.Create. Это не работает, потому что компилятор не знает, что ваш универсальный тип имеет конструктор без параметров (помните: это не требование). Чтобы исправить это, вам нужно создать ограничение конструктора, которое выглядит следующим образом:
<T: constructor>
или, в вашем конкретном случае:
<T: TBaseDatafile, constructor>
@Mason: Я не могу говорить от имени Delphi, и в целом вы правы, что компилятор мог знает, смотрел ли он просто в нужное место. Однако это просто не так, как это работает, чтобы сделать код более явным. Другое дело C++: он не требует таких ограничений в сопоставимых случаях.
@Konrad: Совершенно верно, хороший компилятор, такой как FPC 3.1.1, не нуждается в таких ограничениях, там это прекрасно работает. Очевидно, компилятор Delphi не очень хорош, и это одна из причин, по которой он почти мертв.
Просто быстрое обновление старого вопроса ..
Вам не нужно ограничение конструктора, и вы также можете сделать это для объекта с параметрами, используя 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
Ба. В этом случае компилятор делает знает, что TBaseDataFile имеет виртуальный конструктор, который не принимает параметров.