如何在派生类型中使用泛型方法

Rob*_*Rob 7 delphi generics inheritance delphi-xe3

这看起来相当简单,也许我只是缺少一些语法粘合...这是我的简单泛型(Delphi XE3)示例:

unit Unit1;

interface

uses
  generics.collections;

type

X = class
public
  Id: Integer;
end;

XList<T : X> = class( TObjectList<T> )
 function Find(Id: Integer) : T;
end;

Y = class(X)

end;

YList = class(XList<Y>)
end;

implementation

{ XList<T> }

function XList<T>.Find(Id: Integer): T;
var
  t: X;
begin
  for t in Self do
    if t.Id = Id then
      Result := t;
end;

end.
Run Code Online (Sandbox Code Playgroud)

这不会用"[dcc32错误] Unit1.pas(41)编译:E2010不兼容的类型:'Y'和'X'".这是下线:

YList = class(XList<Y>)
end;
Run Code Online (Sandbox Code Playgroud)

Y来自X所以为什么会出现问题?

Dav*_*nan 8

亚历克斯的答案是解决问题的正确方法.一旦得知答案,它也可以很好地从函数返回.

我想通过更多解释来扩展答案.特别是我想回答你在评论中对Alex的答案提出的问题:

撇开......为什么原来的工作没有?T来自X.

问题代码在这里:

function XList<T>.Find(Id: Integer): T;
var
  t: X;
begin
  for t in Self do
    if t.Id = Id then
      Result := t;
end;
Run Code Online (Sandbox Code Playgroud)

考虑泛型的方法是想象在实例化类型并提供具体类型参数时代码的样子.在这种情况下,让我们来代替TY.然后代码看起来像这样:

function XList_Y.Find(Id: Integer): Y;
var
  t: X;
begin
  for t in Self do
    if t.Id = Id then
      Result := t;
end;
Run Code Online (Sandbox Code Playgroud)

现在您在指定的行中遇到问题Result:

Result := t;
Run Code Online (Sandbox Code Playgroud)

嗯,Result是类型Y,但是t类型X.之间的关系XYY源自X.所以一个例子YX.但一个例子X不是Y.因此,作业无效.

正如Alex正确指出的那样,您需要将循环变量声明为类型T.就个人而言,我会写这样的代码:

function XList<T>.Find(Id: Integer): T;
begin
  for Result in Self do
    if Result.Id = Id then
      exit;
  Result := nil;
  // or perhaps you wish to raise an exception if the item cannot be found
end;
Run Code Online (Sandbox Code Playgroud)

这也解决了搜索例程在未找到项目时未初始化其返回值的问题.这是一个问题,一旦你获得了实际编译的代码,编译器就会警告过这个问题.我希望你启用编译器警告,并在它们出现时处理它们!


Ale*_*xSC 6

我必须按如下方式重新实现Find方法来修复它:

{ XList<T> }

function XList<T>.Find(Id: Integer): T;
var
  item: T;
begin
  for item in Self do
    if item.Id = Id then
      Exit(item);
  Result := nil;
end;
Run Code Online (Sandbox Code Playgroud)

这里最重要的是将变量声明中使用的类型替换XT.

然后,我只是改名从变量t,以item避免名称冲突与类型占位符T和raplaced将Result := item通过Exit(item)返回找到的项目和退出方法.