Delphi 传递给内联函数的匿名函数

Delphi anonymous function passed to inlined function

我偶然发现了一个意想不到的 Delphi 2009 行为。在调查了我的代码中的一个奇怪错误后,我设法缩小了问题的范围并创建了一个最小示例,我将在下面展示。

当然,下面的代码打印值1:

program Example1;

{$APPTYPE CONSOLE}

type
  TIntFcn = reference to function(const X: integer): integer;

function fcn(AFunction: TIntFcn; a: integer): integer; inline;
begin
  result := AFunction(a);
end;

begin

  writeln(fcn(function(const X: integer): integer
    begin
      result := 1;
    end, 0));

end.

同样,这个程序打印值 2:

program Example2;

{$APPTYPE CONSOLE}

type
  TIntFcn = reference to function(const X: integer): integer;

function fcn(AFunction: TIntFcn; a: integer): integer; inline;
begin
  result := AFunction(a);
end;

begin

  writeln(fcn(function(const X: integer): integer
    begin
      result := 2;
    end, 0));

end.

"Obviously",第三个程序打印与第一个相同的值,即 1:

program Produce;

{$APPTYPE CONSOLE}

type
  TIntFcn = reference to function(const X: integer): integer;

function fcn(AFunction: TIntFcn; a: integer): integer; inline;
begin
  result := AFunction(a);
end;

begin

  writeln(fcn(function(const X: integer): integer
    begin
      result := 1;
    end, 0));

  fcn(function(const X: integer): integer
    begin
      result := 2;
    end, 0); // discard the output

end.

但是,输出不是 1,而是 2。似乎编译器在 writeln 中对 fcn 的调用中使用了第二个匿名函数。

对我来说,这似乎是 Delphi 2009 编译器中的一个错误,但也可能只是我不理解 Delphi 中有关匿名函数的更微妙的细节。你怎么看?

这显然是一个错误,根据收到的问题评论,这已在 Delphi XE 中修复。可能最简单的解决方法是在编译器无法正确处理时跳过请求内联:

program Solve;

{$APPTYPE CONSOLE}

type
  TIntFcn = reference to function(const X: integer): integer;

function fcn(AFunction: TIntFcn; a: integer): integer;
  {$IF CompilerVersion >= 22}inline;{$IFEND} {Warning: Horrible bug in Delphi 2009}
begin
  result := AFunction(a);
end;

begin

  writeln(fcn(function(const X: integer): integer
    begin
      result := 1;
    end, 0));

  fcn(function(const X: integer): integer
    begin
      result := 2;
    end, 0); // discard the output

end.

在大多数情况下,性能损失在 Delphi 2009 中应该可以忽略不计,并且您在 XE 和更高版本中确实请求内联。当然,如果您认为内联根本不重要,您可以简单地完全删除请求。