“引用”在Delphi中到底有什么作用?

问题描述

在阅读Anonymous Methods in Delphi上的文档时,我开始感到奇怪。我一直使用这样的东西:

type TMathFn = Function(A,B: Integer): Integer;
var fn: TMathFn;

总是为我工作。但是此文档告诉我改用它:

type TMathFn = Reference to Function(A,B: Integer): Integer;
var fn: TMathFn;

从1994年到2010年,我一直在Delphi中进行开发,因此我对“参考”部分不熟悉。不过,这两种选择似乎都可以正常工作。所以...
它们相同吗?

解决方法

“ REFERENCE TO”允许使用匿名方法(过程/功能的内联定义),该方法可以捕获上下文(例如,本地变量,将其捕获为引用,即,如果在捕获后更改了变量,则为捕获的修改后的值,请参见下文。)

TYPE TMyProc = REFERENCE TO PROCEDURE(CONST S : STRING);

PROCEDURE Information(CONST S : STRING);
  BEGIN
    MessageDlg(S,mtInformation,[mbOK],0)
  END;

PROCEDURE RunProc(P : TMyProc ; CONST S : STRING);
  BEGIN
    P(S)
  END;

PROCEDURE A(B,C : INTEGER);
  VAR
    D : INTEGER;
    P : TMyProc;

  BEGIN
    D:=3;
    // D is 3 at the time of capture
    P:=PROCEDURE(CONST S : STRING)
         BEGIN
           Information(S+': '+IntToStr(D)+' -> '+IntToStr(B))
         END;
    // D is now 4 - and is reflected in the captured routine,as
    // the capture is done by REFERENCE and not by VALUE.
    INC(D);
    RunProc(P,'Hello')
  END;

BEGIN
  A(2,3)
END.

在消息框中将显示“ Hello:4-> 2”。

P的上述定义“捕获”(包括)变量D和B,因此即使将其传递给不存在这些变量的另一个函数,您仍然可以访问它们。

(普通)PROCEDURE [OF OBJECT]类型几乎是不可能的,因为它们无法访问在执行时声明的局部变量。

,

不,它们不相同。

不同之处在于

TMathFn = function(A,B: Integer): Integer;

是一个普通函数,

TMathMethod = function(A,B: Integer): Integer of object;

是一种方法,

TMathAnonMethod = reference to function(A,B: Integer): Integer;

是匿名方法,但是您也可以将普通函数或方法分配给该类型的变量。

例如,如果

type
  TMathFn = function(A,B: Integer): Integer;
  TMathMethod = function(A,B: Integer): Integer of object;
  TMathAnonMethod = reference to function(A,B: Integer): Integer;

function Test(A,B: Integer): Integer;
begin
  Result := A + B;
end;

type
  TTestClass = class
    function Test(A,B: Integer): Integer;
  end;

{ TTestClass }

function TTestClass.Test(A,B: Integer): Integer;
begin
  Result := A + B;
end;

然后适用以下条件:

procedure TForm1.FormCreate(Sender: TObject);
var
  T: TTestClass;
  F: TMathFn;
  M: TMathMethod;
  AM: TMathAnonMethod;
begin

  T := TTestClass.Create;
  try

    F := Test; // compiles
    F := T.Test; // doesn't compile
    F := function(A,B: Integer): Integer
      begin
        Result := A + B;
      end; // doesn't compile

    M := Test; // doesn't compile
    M := T.Test; // compiles
    M := function(A,B: Integer): Integer
      begin
        Result := A + B;
      end; // doesn't compile

    AM := Test; // compiles
    AM := T.Test; // compiles
    AM := function(A,B: Integer): Integer
      begin
        Result := A + B;
      end; // compiles

  finally
    T.Free;
  end;

end;

在后台,您可能已经知道,F只是一个(函数)指针,而M是一个method pointer。另一方面,匿名方法则具有更多的基于接口的实现,这允许其发挥所有魔力(如变量捕获)。