Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi'中如何以及何时引用变量;捕获了哪些匿名方法?_Delphi_Delphi 2010_Anonymous Methods - Fatal编程技术网

Delphi'中如何以及何时引用变量;捕获了哪些匿名方法?

Delphi'中如何以及何时引用变量;捕获了哪些匿名方法?,delphi,delphi-2010,anonymous-methods,Delphi,Delphi 2010,Anonymous Methods,这是因为,特别是大卫对巴里问题的评论。因为我没有一个博客可以发布这篇文章,所以我将在这里问这个问题,并回答它 问题:在Delphi的匿名方法中何时以及如何引用变量 例如: procedure ProcedureThatUsesAnonymousMethods; var V: string; F1: TFunc<string>; F2: TFunc<string>; begin F1 := function: string begin

这是因为,特别是大卫对巴里问题的评论。因为我没有一个博客可以发布这篇文章,所以我将在这里问这个问题,并回答它

问题:在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;
使用匿名方法的过程;
变量V:字符串;
F1:TFunc;
F2:TFunc;
开始
F1:=函数:字符串
开始
结果:=V;//引用局部变量
结束
V:='1';
F2:=函数:字符串
开始
结果:=V;
结束
V:='2';
ShowMessage(F1);
ShowMessage(F2);
结束;

两个
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 light
procedure 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;

在SO发帖对社区也更有帮助。(当然,你在这里发帖会获得更多的声誉!:)嗯。。。如果函数/过程不属于对象,它们是否被称为“方法”?您使用的是哪个delphi版本?@Andreas,只有当它们属于类时,我才称它们为“方法”。我只是重新阅读了问题和答案,如果我真的把两者混在一起,我就看不出其中的混淆:——(我在想
ProcedureThatUsesAnonymousMethods;
我到目前为止从未想过这一点,但即使
F1
F2
都是匿名的,它们是匿名的方法吗?
unit Unit25;

interface

uses
  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.