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所以为什么会出现问题?
亚历克斯的答案是解决问题的正确方法.一旦得知答案,它也可以很好地从函数返回.
我想通过更多解释来扩展答案.特别是我想回答你在评论中对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)
考虑泛型的方法是想象在实例化类型并提供具体类型参数时代码的样子.在这种情况下,让我们来代替T
用Y
.然后代码看起来像这样:
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
.之间的关系X
和Y
是Y
源自X
.所以一个例子Y
是X
.但一个例子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)
这也解决了搜索例程在未找到项目时未初始化其返回值的问题.这是一个问题,一旦你获得了实际编译的代码,编译器就会警告过这个问题.我希望你启用编译器警告,并在它们出现时处理它们!
我必须按如下方式重新实现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)
这里最重要的是将变量声明中使用的类型替换X
为T
.
然后,我只是改名从变量t
,以item
避免名称冲突与类型占位符T
和raplaced将Result := item
通过Exit(item)
返回找到的项目和退出方法.