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

Delphi 如何在派生类型中使用泛型方法,delphi,generics,inheritance,delphi-xe3,Delphi,Generics,Inheritance,Delphi Xe3,这看起来相当简单,也许我只是缺少了一点语法胶水。。。下面是我的简单通用(Delphi XE3)示例: 单元1; 接口 使用 仿制药;收藏; 类型 X=类 公众的 Id:整数; 结束; XList=类(TObjectList) 函数Find(Id:Integer):T; 结束; Y=等级(X) 结束; YList=class(XList) 结束; 实施 {XList} 函数XList.Find(Id:Integer):T; 变量 t:X; 开始 为自己做的事 如果t.Id=Id,则 结果:=t;

这看起来相当简单,也许我只是缺少了一点语法胶水。。。下面是我的简单通用(Delphi XE3)示例:

单元1;
接口
使用
仿制药;收藏;
类型
X=类
公众的
Id:整数;
结束;
XList=类(TObjectList)
函数Find(Id:Integer):T;
结束;
Y=等级(X)
结束;
YList=class(XList)
结束;
实施
{XList}
函数XList.Find(Id:Integer):T;
变量
t:X;
开始
为自己做的事
如果t.Id=Id,则
结果:=t;
结束;
结束。
这将不会使用“[dcc32 Error]Unit1.pas(41):E2010不兼容类型:‘Y’和‘X’”进行编译。具体到:

YList = class(XList<Y>)
end;
YList=class(XList)
结束;

Y源于X,为什么会出现问题?

我必须按如下方式重新实现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;
{XList}
函数XList.Find(Id:Integer):T;
变量
项目:T;
开始
对于自办项目
如果item.Id=Id,则
出口(项目);
结果:=无;
结束;
这里重要的是将变量声明中使用的类型从
X
替换为
T


然后我将变量从
t
重命名为
item
,以避免与类型占位符
t
发生名称冲突,并通过
Exit(item)
重新放置
结果:=item
,以返回找到的项并退出该方法。

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;
现在,分配给
结果的行出现问题:

Result := t;
嗯,
Result
Y
类型,但是
t
X
类型。
X
Y
之间的关系是
Y
源自
X
。所以
Y
的一个实例是
X
。但是
X
的实例不是
Y
。所以这个赋值是无效的

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

function XList_Y.Find(Id: Integer): Y;
var
  t: X;
begin
  for t in Self do
    if t.Id = Id then
      Result := t;
end;
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;
函数XList.Find(Id:Integer):T;
开始
因为结果是自作主张
如果Result.Id=Id,则
出口
结果:=无;
//或者,如果找不到该项,您可能希望引发异常
结束;

这还解决了一个问题,即如果找不到项目,搜索例程将其返回值保持为未初始化状态。这是一个问题,一旦您得到了实际编译的代码,编译器就会发出警告。我希望您启用编译器警告,并在出现警告时处理它们

很棒的东西@AlexSC。我最初有“var t:t”。我已经忘记了案件不敏感。我的C#仿制药的东西挡住了去路!作为旁白。。。为什么原著没有被修改?T是从X派生出来的。@Rob:对不起,我没有答案。对我来说,编译器在单元的最后一行找到了错误消息,这表明它与泛型类型实例化有关。在泛型方面,编译器似乎对类型匹配非常严格。@Rob,如果你想知道原因,请阅读David的答案:@whosrdaddy它实际上比泛型变体更平淡无奇。我添加了一个答案来解释。
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;