delphi - 匿名方法在幕后是如何实现的?

标签 delphi anonymous-methods

Delphi 是否“实例化”每个匿名方法(如对象)?如果是,Delphi 何时创建此实例,最重要的是,Delphi 何时释放它?

由于匿名方法还会捕获外部变量并延长其生命周期,因此了解这些变量何时从内存中“释放”非常重要。

在另一个匿名方法中声明一个匿名方法可能有哪些缺点。 可以循环引用吗?

最佳答案

匿名方法作为接口(interface)实现。本文很好地解释了编译器是如何完成的:Anonymous methods in Delphi: the internals .

本质上,编译器生成的接口(interface)有一个名为 Invoke 的方法,其后面是您提供的匿名方法。

捕获的变量与捕获它们的任何匿名方法具有相同的生命周期。匿名方法是一个接口(interface),其生命周期由引用计数管理。因此,捕获的变量的生命周期与捕获它们的匿名方法一样长。

正如可以使用接口(interface)创建循环引用一样,也同样可以使用匿名方法创建循环引用。这是我可以构建的最简单的演示:

uses
  System.SysUtils;

procedure Main;
var
  proc: TProc;
begin
  proc :=
    procedure
    begin
      if Assigned(proc) then
        Beep;
    end;
end;

begin
  ReportMemoryLeaksOnShutdown := True;
  Main;
end.

编译器在幕后创建一个实现匿名方法接口(interface)的隐藏类。该类包含捕获的任何变量作为数据成员。当分配 proc 时,会增加实现实例的引用计数。由于 proc 由实现实例所有,因此该实例已引用其自身。

为了让这一点更清楚一些,该程序提出了相同的问题,但在界面方面进行了重新设计:

uses
  System.SysUtils;

type
  ISetValue = interface
    procedure SetValue(const Value: IInterface);
  end;

  TMyClass = class(TInterfacedObject, ISetValue)
    FValue: IInterface;
    procedure SetValue(const Value: IInterface);
  end;

procedure TMyClass.SetValue(const Value: IInterface);
begin
  FValue := Value;
end;

procedure Main;
var
  intf: ISetValue;
begin
  intf := TMyClass.Create;
  intf.SetValue(intf);
end;

begin
  ReportMemoryLeaksOnShutdown := True;
  Main;
end.

可以通过显式清除自引用来打破循环。在匿名方法示例中,如下所示:

procedure Main;
var
  proc: TProc;
begin
  proc :=
    procedure
    begin
      if Assigned(proc) then
        Beep;
    end;
  proc := nil;
end;

接口(interface)变体的等效项是:

procedure Main;
var
  intf: ISetValue;
begin
  intf := TMyClass.Create;
  intf.SetValue(intf);
  intf.SetValue(nil);
end;

关于delphi - 匿名方法在幕后是如何实现的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39955052/

相关文章:

C# 不能在匿名方法体内使用 ref 或 out 参数

c# - 使用 Func<> 参数将委托(delegate)对象传递给方法

delphi - InternetReadFile 的常见平均缓冲区大小是多少?

c# - 为同一个匿名方法创建两个委托(delegate)实例不相等

c# - 什么允许匿名无参数委托(delegate)类型有所不同?

delphi - 在注册表中将数据设置为子项时出错

c# - 在匿名方法中使用 MethodInfo.GetCurrentMethod()

python - 通过套接字传递记录

delphi - 向 Delphi 推荐新功能的最佳方式是什么?

delphi - 在 Delphi 中为 TObject 分配属性