松开“分配给程序变量的本地程序/功能””限制优雅

考虑以下测试用例:
{ CompilerVersion = 21 }
procedure Global();

  procedure Local();
  begin
  end;

type
  TProcedure = procedure ();
var
  Proc: TProcedure;
begin
  Proc := Local;  { E2094 Local procedure/function 'Local' assigned to procedure variable }
end;
在第13行,编译器发出具有ERROR级别的消息,禁止所有这种本地过程使用的情况。 “官方”决议是将
Local
符号提升到外部范围(即:使其成为
Global
的兄弟),这将对代码“结构性”产生负面影响。 我正在寻找以最优雅的方式绕过它的方法,最好是让编译器发出警告级别的消息。     
已邀请:
您最好的选择是使用新的匿名方法功能将其声明为
reference to procedure
,然后您可以保持所有内容的良好封装。
type
  TProc = reference to procedure;

procedure Outer;
var
  Local: TProc;
begin
  Local := procedure
    begin
      DoStuff;
    end;
  Local;
end;
这通过捕获匿名函数本地的任何变量来解决Mason描述的问题。     
这就是为什么你不能这样做的原因:
type
  TProcedure = procedure ();

function Global(): TProcedure;
var
  localint: integer;

  procedure Local();
  begin
    localint := localint + 5;
  end;

begin
  result := Local;
end;
本地过程可以访问外部例程的变量范围。但是,这些变量在堆栈上声明,并且在外部过程返回后变为无效。 但是,如果您正在使用CompilerVersion 21(Delphi 2010),那么您可以使用匿名方法,这些方法应该能够满足您的需求;你需要一个稍微不同的语法。     
如果真的需要在D7或更早版本中使用本地程序,可以使用这个技巧:
procedure GlobalProc;
var t,maxx:integer; itr,flag1,flag2:boolean; iterat10n:pointer;
    //Local procs:
    procedure iterat10n_01;begin {code #1 here} end;
    procedure iterat10n_10;begin {code #2 here} end;
    procedure iterat10n_11;begin {code #1+#2 here} end;
begin
    //...
    t:=ord(flag2)*$10 or ord(flag1);
    if t=$11 then iterat10n:=@iterat10n_11
      else if t=$10 then iterat10n:=@iterat10n_10
        else if t=$01 then iterat10n:=@iterat10n_01
          else iterat10n:=nil;
    itr:=(iterat10n<>nil);
    //...
    for t:=1 to maxx do begin
        //...
        if(itr)then asm
            push ebp;
            call iterat10n;
            pop ecx;
        end;
        //...
    end;
    //...
end;
然而问题是地址寄存器在不同的机器上会有所不同 - 因此需要使用本地proc调用来编写一些代码,并通过断点查看哪些寄存器在那里使用... 是的 - 在大多数真实的制作案例中,这个技巧只是某种缓和。     
对于记录,我的homebrewn关闭:
{ this type looks "leaked" }
type TFunction = function (): Integer;

function MyFunction(): TFunction;

  {$J+ move it outside the stack segment!}
  const Answer: Integer = 42;

  function Local(): Integer;
  begin
    Result := Answer;
    { just some side effect }
    Answer := Answer + Answer div 2;
  end;

begin
  Result := @Local;
end;


procedure TForm1.FormClick(Sender: TObject);
var
  Func: TFunction;
  N: Integer;
begin
  { unfolded for clarity }
  Func := MyFunction();
  N := Func();
  ShowMessageFmt('Answer: %d', [N]);
end;
    

要回复问题请先登录注册