这看起来相当简单,也许我只是缺少一些语法粘合...这是我的简单通用(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.
这不会用“[dcc32错误] Unit1.pas(41)编译:E2010不兼容的类型:'Y'和'X'”。这是下线:
YList = class(XList<Y>)
end;
Y来自X,为什么会出现问题?
答案 0 :(得分:8)
Alex的答案是解决问题的正确方法。一旦知道答案,它也可以很好地从函数返回。
我想通过更多解释来扩展答案。特别是我想回答你在评论中对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;
考虑泛型的方法是想象在实例化类型并提供具体类型参数时代码的样子。在这种情况下,我们将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;
现在,您在分配给Result
的行中遇到问题:
Result := t;
嗯,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;
这也解决了搜索例程在未找到项目时未初始化其返回值的问题。这是一个问题,一旦你获得了实际编译的代码,编译器就会警告过这个问题。我希望你启用编译器警告,并在它们出现时处理它们!
答案 1 :(得分: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;
这里重要的是将变量声明中使用的类型从X
替换为T
。
然后我只是将变量从t
重命名为item
,以避免与类型占位符T
发生名称冲突,并将Result := item
替换为Exit(item)
返回找到的项目并退出方法。