Дженерик без конструкторов без параметров

Обновить

November 2018

Просмотры

127 раз

3

Может кто - нибудь объяснить , почему в коде ниже, class1List вовсе не требует Class1 иметь конструктор без параметров, но class2list делает требуется класс 2 , чтобы иметь конструктор без параметров.

unit Unit11;

interface

uses
  System.Generics.Collections;

type
  class1 = class
  public
    constructor Create( const i : integer ); virtual;
  end;

  class1List<T : class1 > = class( TObjectList< T > )
  public
    function AddChild( const i : integer ) : T;
  end;

  class2 = class
  public
    constructor Create( const i : integer );
  end;

  class2List<T : class2 > = class( TObjectList< T > )
  public
    function AddChild( const i : integer ) : T;
  end;


implementation

{ class1List<T> }

function class1List<T>.AddChild(const i: integer): T;
begin
  Result := T.Create( i );
  inherited Add( Result );
end;

{ class2List<T> }

function class2List<T>.AddChild(const i: integer): T;
begin
  Result := T.Create( i );
  inherited Add( Result );
end;

{ class1 }

constructor class1.Create(const i: integer);
begin

end;

{ class2 }

constructor class2.Create(const i: integer);
begin

end;

end.
Dsm

1 ответы

4
function class1List<T>.AddChild(const i: integer): T;
begin
  Result := T.Create( i );
  inherited Add( Result );
end;

Конструктор class1объявляется virtual. Поэтому компилятор знает , что T.Createдает экземпляр Tкоторого предназначен конструктор был вызван. Поэтому компилятор принимает этот код. Обратите внимание , что более ранние версии компилятора отвергнут этот код и заставит вас использовать следующий бросок

Result := T(class1(T).Create( i ));

Но более поздние версии компилятора удалили необходимость такого обмана.


function class2List<T>.AddChild(const i: integer): T;
begin
  Result := T.Create( i );
  inherited Add( Result );
end;

Конструктор class2не virtualтак компилятор знает , что если бы вызвать конструктор class2, вероятно , класс не будет правильно инициализируется. Он готов вызвать конструктор без параметров из специализированного типа , Tесли таковой существует, и вы применить constructorограничения при объявлении универсального типа. Тем не менее, язык не дает никакой возможности применить конструктор ограничение для конструкторов , которые принимают параметры.

Теперь вы можете применить constructorограничение, но это не будет делать ничего хорошего. Для того , чтобы экземпляр будет инициализирован должным образом, вам нужно вызвать конструктор с параметром. Это означает, в практическом плане, что вы должны использовать первый подход с использованием виртуального конструктора.

Не поддавайтесь искушению, чтобы бросить свой путь из этой дыры. Этот код будет компилироваться

Result := T(class2(T).Create( i ));

но, вероятно , не делать то , что вы хотите. Это будет вызывать статический конструктор , class2который , конечно , не то , что вы хотите.