Анонимные методы реализованы как интерфейсы. В этой статье есть хорошее объяснение того, как это делается компилятором: Anonymous methods in Delphi: the internals.
По существу, сгенерированный компилятором интерфейс имеет один метод с именем Invoke
, за которым вы предоставляете анонимный метод.
Захваченные переменные имеют одинаковую продолжительность жизни, как и любые анонимные методы, которые их захватывают. Анонимный метод - это интерфейс, и его время жизни управляется подсчетом ссылок. Следовательно, захваченные переменные жизни продлеваются до тех пор, пока анонимные методы их захватывают.
Как можно создавать круглые ссылки с интерфейсами, одинаково возможно создание круговых ссылок с использованием анонимных методов. Вот самая простая демонстрация того, что я могу построить:
uses
System.SysUtils;
procedure Main;
var
proc: TProc;
begin
proc :=
procedure
begin
if Assigned(proc) then
Beep;
end;
end;
begin
ReportMemoryLeaksOnShutdown := True;
Main;
end.
За кулисы компилятор создает скрытый класс, который реализует интерфейс анонимного метода. Этот класс содержит в качестве элементов данных любые перенесенные переменные. Когда назначается 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;
эквивалент для варианта интерфейса является:
procedure Main;
var
intf: ISetValue;
begin
intf := TMyClass.Create;
intf.SetValue(intf);
intf.SetValue(nil);
end;
Смотрите также [Переменный Binding Механизм] (http://docwiki.embarcadero.com/RADStudio/о/Anonymous_Methods_in_Delphi # Variable_Binding_Mechanism). –
См. Также: http://blog.barrkel.com/2008/07/anonymous-method-details.html –
FWIW, Барри Келли реализовал анонимные методы. –