在Delphi的匿名方法中引用的变量和何时被捕获?

在Delphi的匿名方法中引用的变量和何时被捕获?,第1张

概述这是由 How to compare TFunc/TProc containing function/procedure of object?提出的,特别是David对Barry的问题的评论。因为我没有一个博客来发布这个,我将在这里提出这个问题,并回答。 问题:Delphi的匿名方法中引用变量何时和如何被捕获? 例: procedure ProcedureThatUsesAnonymousMet 这是由 How to compare TFunc/TProc containing function/procedure of object?提出的,特别是DavID对barry的问题的评论。因为我没有一个博客来发布这个,我将在这里提出这个问题,并回答。

问题:Delphi的匿名方法中引用的变量何时和如何被捕获?

例:

procedure ProcedureThatUsesAnonymousMethods;var V: string;    F1: TFunc<string>;    F2: TFunc<string>;begin  F1 := function: string        begin          Result := V; // references local variable        end  V := '1';  F2 := function: string        begin          Result := V;        end V := '2'; ShowMessage(F1); ShowMessage(F2);end;

ShowMessage都会显示2.为什么? V如何被捕获和什么时候?

解决方法 当您有一个类似于问题中的函数时,您有匿名方法访问局部变量,Delphi似乎创建一个TInterfacedobject后代,它捕获所有基于堆栈的变量,因为它是自己的公共变量。使用barry的技巧来实现TObject和一些RTTI,我们可以看到这一切都在行动中。

执行后面的魔术代码可能如下所示:

// Magic object that holds what would normally be Stack variables and implements// anonymous methods.type ProcedureThatUsesAnonymousMethods$ActRec = class(TInterfacedobject)public  V: string;  function AnonMethodImp: string;end;// The procedure with all the magic brought to lightprocedure ProcedureThatUsesAnonymousMethods;var MagicInterface: IUnkNown;    F1: TFunc<string>;    F2: TFunc<string>;begin  MagicInterface := ProcedureThatUsesAnonymousMethods$ActRec.Create;  try    F1 := MagicInterface.AnonMethod;    MagicInterface.V := '1';    F2 := MagicInterface.someOtherAnonMethod;    MagicInterface.V := '2';    ShowMessage(F1);    ShowMessage(F2);  finally MagicInterface := nil;  end;end;

当然这个代码没有编译。我是无魔法的:-)但是这里的想法是在幕后创建了一个“魔术”对象,并且从匿名方法引用的局部变量被转换为魔术对象的公共字段。该对象用作接口(IUnkown),因此它被引用计数。显然,相同的对象捕获所有使用的变量,并定义所有匿名方法。

这应该回答“何时”和“如何”。

这是我以前调查的代码。把一个Tbutton放在空白的表单上,这应该是整个单位。当您按下按钮时,您将在屏幕上看到以下内容:

> 000000(虚假号码)
> 000000(相同数字):这两个匿名方法的证明实际上是作为同一个对象的方法实现的!
> TForm25.button1Click $ ActRec:TInterfacedobject:这显示了实现后面的对象,它来自于TInterfacedobject
> OnStack:string:RTTI发现该对象上的该字段。
> Self:TForm25:RTTI发现该对象上的该字段。它用于获取ClasVar的值
> FRefCount:Integer – 这来自TInterfacedobject
> Class Var – ShowMessage的结果。
>堆栈 – ShowMessage的结果。

以下是代码:

unit Unit25;interfaceuses  windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,Dialogs,StdCtrls,Rtti;type  TForm25 = class(TForm)    button1: Tbutton;    procedure button1Click(Sender: TObject);  private    ClassVar: string;  public  end;var  Form25: TForm25;implementation{$R *.dfm}procedure TForm25.button1Click(Sender: TObject);var F1: TFunc<string>;    F2: TFunc<string>;    OnStack: string;    i: IInterface;    o: TObject;    RC: TRttiContext;    R: TRttiType;    RF: TRttiFIEld;begin  // This anonymous method references a member fIEld of the TForm class  F1 := function :string        begin          Result := ClassVar;        end;  i := PUnkNown(@F1)^;  o := i as TObject;  ShowMessage(IntToStr(Integer(o))); // I'm looking at the pointer to see if it's the same instance as the one for the other Anonymous method  // This anonymous method references a stack variable  F2 := function :string        begin          Result := OnStack;        end;  i := PUnkNown(@F2)^;  o := i as TObject;  ShowMessage(IntToStr(Integer(o)));  ShowMessage(o.Classname + ': ' + o.Classtype.Classparent.Classname);  RC.Create;  try    R := RC.GetType(o.Classtype);    for RF in R.GetFIElds do      ShowMessage(RF.name + ':' + RF.FIEldType.name);  finally RC.Free;  end;  ClassVar := 'Class Var';  OnStack := 'On Stack';  ShowMessage(F1);  ShowMessage(F2);end;end.
总结

以上是内存溢出为你收集整理的在Delphi的匿名方法中引用的变量和何时被捕获?全部内容,希望文章能够帮你解决在Delphi的匿名方法中引用的变量和何时被捕获?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1280688.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-09
下一篇 2022-06-09

发表评论

登录后才能评论

评论列表(0条)

保存