代码之家  ›  专栏  ›  技术社区  ›  gabr

Delphi 2009中的匿名程序

  •  5
  • gabr  · 技术社区  · 16 年前

    以下代码(仅用于演示问题)在Delphi2010中编译并运行。在Delphi2009中,编译器因“E2035没有足够的实际参数”而失败。

    program Project50;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils;
    
    type
      TMyProc = reference to procedure(param: integer);
    
    var
      a: TProc;
      b: TMyProc;
    
    begin
      b := procedure (param: integer)
        begin
        end;
      a := TProc(b); // <-- [DCC Error] Project50.dpr(19): E2035 Not enough actual parameters
    end.
    

    我发现只有一个非常丑陋的黑客可以解决这个问题(a:tproc absolute b)。有人知道有更好的解决这个编译器缺陷的方法吗?

    [tproc字段实际上隐藏在一个可以存储各种“可执行”代码的记录中—tprocedure、tmethod和tproc。casting用于将特定匿名进程存储到此字段。]

    3 回复  |  直到 16 年前
        1
  •  1
  •   kludg    16 年前

    我发现了一个黑客2:

    program Project1;
    
    {$APPTYPE CONSOLE}
    
    
    uses
      SysUtils;
    
    type
      TMyProc = reference to procedure(param: integer);
    
    var
      a: TProc;
      b: TMyProc;
    
    begin
      b := procedure (param: integer)
        begin
          Writeln('asdf');
        end;
      PPointer(@a)^ := PPointer(@b)^;
      a;
      readln;
    end.
    

    我怀疑您试图通过将tmyproc(带有param参数)分配给tproc(不带参数)来实现什么?


    更新的 :一个黑客3(应该增加参考计数器,这个想法是从系统中窃取的。_intfcopy):

    procedure AnonCopy(var Dest; const Source);
    var
      P: Pointer;
    
    begin
      P:= Pointer(Dest);
      if Pointer(Source) <> nil
        then IInterface(Source)._AddRef;
      Pointer(Dest):= Pointer(Source);
      if P <> nil then
        IInterface(P)._Release;
    end;
    
    var
      a: TProc;
      b: TMyProc;
    
    begin
      b := procedure (param: integer)
        begin
          Writeln('asdf');
        end;
      AnonCopy(a, b);
    //  PPointer(@a)^ := PPointer(@b)^;
      a;
      readln;
    end.
    
        2
  •  2
  •   gabr    16 年前

    诀窍是不做

    a := TProc(b);
    

    但是

    TMyProc(a) := b;
    

    它编译并在D2009中工作。附在下面的示例项目。

    program Project51;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils;
    
    type
      TMyProc = reference to procedure(var param: integer);
    
      TStorage = record
        FDelegate: TProc;
      end;
    
    var
      a    : TMyProc;
      b    : TMyProc;
      param: integer;
      stg  : TStorage;
    
    begin
      b := procedure (var param: integer)
        begin
          param := 2*param;
        end;
    //  stg.FDelegate := TMyProc(b); // doesn't compile in Delphi 2009, compiles in Delphi 2010
      TMyProc(stg.FDelegate) := b;
      param := 21;
      TMyProc(stg.FDelegate)(param);
      Writeln(param);
      Readln;
    end.
    

    但是,如果强制转换为局部变量,则不起作用。

    var
      p: TProc;
      a: TMyProc;
    
    TMyProc(p) := a; // this will not compile
    

    保管人和保管人。

        3
  •  1
  •   gabr    16 年前

    似乎最好的方法是使用泛型在记录中存储正确类型的委托。不需要黑客。

    program Project51;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils;
    
    type
      TMyProc = reference to procedure(var param: integer);
    
      TStorage<T> = record
        FDelegate: T;
      end;
    
    var
      a    : TMyProc;
      b    : TMyProc;
      p    : TProc;
      param: integer;
      stg  : TStorage<TMyProc>;
    
    begin
      b := procedure (var param: integer)
        begin
          param := 2*param;
        end;
      stg.FDelegate := b;
      param := 21;
      stg.FDelegate(param);
      Writeln(param);
      Readln;
    end.