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/