Delphi通用模板类用法编译错误

时间:2016-03-26 13:14:05

标签: delphi generics compiler-errors

我是Delphi Generic Classes的新手。我不知道如何在实现代码中使用泛型类。 这是代码:

Type TDataElement = class(TObject)
  protected
    Procedure SetName(sNewValue:String); virtual;
  private
    m_sName:String;
  published
    property sName:String read m_sName write SetName;
end;

Type TDataArray<T : TDataElement> = class(TObject)
  public

    function Find(dtElement:T):integer; 
    Procedure Add(dtElement:T);
  private
    m_vContainer : array of T;
  protected
    Function GetData(Index:integer):T; virtual;
    Procedure SetData(Index:integer; NewValue:T); virtual;
  public
    property vData[Index: Integer]: T read GetData write SetData;
end;

implementation

function TDataArray<T>.Find(dtElement:T):integer;
var i:integer;
begin
  Result:=-1;
  for i := 0 to high(m_vContainer) do
    if (m_vContainer[i] <> NIL)and(m_vContainer[i] = dtElement) then
    begin
      Result:=i;
      exit;
    end;
end;    
.....

当我尝试创建Generic Classes的实例时,如下面的代码: 的方法1)

var z:TDataArray<TDataElement>;
    z:=TDataArray<TDataElement>.Create();

我收到以下错误:

E2010不兼容的类型:&#39; TDataElement&#39;和&#39;类TDataElement&#39;

如果我做第二种方法,我会得到另一个奇怪的错误: 方法2)     类型TDataElementClass = TDataElement的类;

var  z:TDataArray<TDataElementClass>;

F2084内部错误:I8230

我做错了什么?

一个文件中的整个源代码

  System.SysUtils,Classes,
  dtArray_unit in 'D:\VisionBot\Software\VisionBot\GUI\Units\dtArray_unit.pas';


Type TDataElement = class(TObject)
  protected
    Procedure SetName(sNewValue:String); virtual;
  private
    m_sName:String;
  published
    property sName:String read m_sName write SetName;
end;

Type TDataArray<T : TDataElement> = class(TObject)
  public

    function Find(dtElement:T):integer; overload;

    Procedure Add(dtElement:T);
  private

    m_vContainer : array of T;
  protected
    Function GetData(Index:integer):T; virtual;
    Procedure SetData(Index:integer; NewValue:T); virtual;
  public
    property vData[Index: Integer]: T read GetData write SetData;
end;

type
  TDerivedDataElement = class(TDataElement)
  end;

var
  z2: TDataArray<TDerivedDataElement>;


//------------------------------------------------------------------------------
Procedure TDataElement.SetName(sNewValue:String);
begin
  self.m_sName:=sNewValue;
end;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
function TDataArray<T>.Find(dtElement:T):integer;
var i:integer;
begin
  Result:=-1;
  for i := 0 to high(m_vContainer) do
    if (m_vContainer[i] <> NIL)and(m_vContainer[i] = dtElement) then
    begin
      Result:=i;
      exit;
    end;
end;
//------------------------------------------------------------------------------
Function TDataArray<T>.GetData(Index:integer):T;
begin
  Result:=NIL;
  if Index < 0 then exit else
  if Index > high(Index) then exit else
  Result:=self.m_vContainer[Index];
end;
//------------------------------------------------------------------------------
Procedure TDataArray<T>.Add(dtElement:T);
begin
  SetLength(self.m_vContainer,Length(m_vContainer)+1);
  m_vContainer[High(m_vContainer)]:=T;
end;
//------------------------------------------------------------------------------
Procedure TDataArray<T>.SetData(Index:integer; NewValue:T);
begin
  if Index < 0 then exit else
  if Index > high(Index) then exit else
  self.m_vContainer[Index]:=T;

end;
//------------------------------------------------------------------------------


begin
  try

    z2:= TDataArray<TDerivedDataElement>.Create();

    readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

1 个答案:

答案 0 :(得分:4)

var  
  z: TDataArray<TDataElementClass>;

问题是TDataElementClass不是从TDataElement派生的类。

以下内容有效:

var  
  z: TDataArray<TDataElement>;

或者这个:

type
  TDerivedDataElement = class(TDataElement)
  end;

var  
  z: TDataArray<TDerivedDataElement>;

在您的代码中

type
  TDataElementClass = class of TDataElement;

现在,TDataElementClassmetaclass

  • TDataElement类型的变量可以包含TDataElement类型的实例,或者来自TDataElement的任何类的实例。
  • TDataElementClass类型的变量可以包含类型,必须为TDataElement,或者来自TDataElement的任何类。

您在问题中声称使用TDataArray<TDataElement>会导致编译器错误,但事实并非如此。考虑一下这个编译程序:

type
  TDataElement = class
  end;

type
  TDataArray<T: TDataElement> = class
  public
    function Find(dtElement: T): Integer;
  private
    m_vContainer: array of T;
  end;

function TDataArray<T>.Find(dtElement: T): Integer;
begin
  for Result := 0 to high(m_vContainer) do
    if (m_vContainer[Result] <> nil) and (m_vContainer[Result] = dtElement) then
      exit;
  Result := -1;
end;

var
  arr: TDataArray<TDataElement>;

begin
  arr := TDataArray<TDataElement>.Create;
end.

在编辑中显示以下代码:

Procedure TDataArray<T>.Add(dtElement:T);
begin
  SetLength(self.m_vContainer,Length(m_vContainer)+1);
  m_vContainer[High(m_vContainer)]:=T;
end;

错误的一行在这里:

m_vContainer[High(m_vContainer)]:=T;

这会失败,因为T是一个类型而不是一个实例。我想你的意思是:

m_vContainer[High(m_vContainer)]:=dtElement;