delphi - 返回带有接口(interface)字段的记录的函数

标签 delphi delphi-xe

询问后this question about interface fields in records我假设以下内容可行(注意断言):

type
  TRec <T> = record
    Intf : IInterface;
  end;

  TTestClass = class
  public
    function ReturnRec : TRec <Integer>;
  end;

  // Implementation 
  function TTestClass.ReturnRec : TRec <Integer>;
  begin
    Assert (Result.Intf = nil);    // Interface field in record should be initialized!
    Result.Intf := TInterfacedObject.Create;
  end;

我使用以下代码对此进行了测试:

  for I := 1 to 1000 do
    Rec := Test.ReturnRec;

断言失败!

我的错误在哪里?什么假设是错误的?

最佳答案

功能

function ReturnRec: TRec<Integer>;

语义上等于过程

procedure ReturnRec(var Result: TRec<Integer>);

[我很确定来自 Embarcadero 的人,可能是 Barry Kelly 或 Alan Bauer 在某处说过这一点,但我目前找不到引用资料。]

在第二种情况下,编译器假定记录在传递给 ReturnRec 之前将被初始化(如果需要),并且不会在 ReturnRec 内为 rec 创建任何初始化代码。我假设第一个示例采用编译器内相同的代码路径,这就是结果未初始化的原因。

无论如何,解决方案很简单:

function TTestClass.ReturnRec : TRec <Integer>;
begin
  Result.Intf := TInterfacedObject.Create;
end;

假设编译器知道它在做什么并分配接口(interface),一切都会正常工作。

编辑

您遇到的问题是由“for”循环引起的。您的代码

for I := 1 to 1000 do
  Rec := Test.ReturnRec;

被编译成这样的东西:

var
  result: TRec<Integer>;

Initialize(result);
for I := 1 to 1000 do begin
  Test.ReturnRec(result);
  rec := result;
end;

这就是为什么您要重复使用相同的记录,这就是为什么 Result.Intf 仅在第一次时未初始化。

编辑2

您可以通过将 t.ReturnRec 调用从循环移出到单独的方法中来欺骗编译器。

procedure GetRec(t: TTest; var rec: TRec);
begin
  rec := t.ReturnRec;
end;

for i := 1 to 1000 do
  GetRec(t, rec);

现在,隐藏的结果变量位于 GetRec 过程中,并在每次调用 GetRec 时进行初始化。

关于delphi - 返回带有接口(interface)字段的记录的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8518992/

相关文章:

delphi - TIdHTTPServer 放置在 DLL 中时卡在 Free() 上

delphi - Delphi 中的游戏开发

delphi - 自定义属性编辑器 - 它们似乎从未出现

delphi - 是否可以在 delphi 类上定义虚拟静态成员?

delphi - TClientDataSet 过滤器是否有限制,或者是一个错误?

delphi - 删除Delphi中标签之间变量子字符串的所有实例

delphi - 德尔福ABS功能失效

delphi - 如何在 TDBCtrlGrid 上启用鼠标滚轮滚动?

delphi - 阻塞套接字会触发哪些事件?

mysql - 如何从delphi在SQL中使用节中的变量