【问题标题】:Casting anonymous procedures in Delphi 2009在 Delphi 2009 中铸造匿名程序
【发布时间】:2011-01-19 10:04:04
【问题描述】:

以下代码(仅用于演示问题)在 Delphi 2010 中编译并运行。在 Delphi 2009 中,编译器失败并显示“E2035 Not enough actual parameters”。

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.

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

[TProc 字段实际上隐藏在可以存储各种“可执行”代码的记录中 - TProcedure、TMethod 和 TProc。 Casting 用于将特定的匿名 proc 存储到该字段中。]

【问题讨论】:

    标签: delphi delphi-2009 anonymous-methods


    【解决方案1】:

    诀窍是不做

    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
    

    好奇者和好奇者。

    【讨论】:

      【解决方案2】:

      我发现了一个 hack #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(带参数参数)分配给 TProc(不带参数)来实现什么?


      更新:技巧 #3(应该增加 ref 计数器,这个想法是从 System._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.
      

      【讨论】:

      • 它适用于测试用例,但不适用于我的(稍微复杂一点的)用例。那里的接口引用计数出了点问题。我将尝试整理一个更准确的测试用例。 TProc 只是不同“参考程序”实体的存储区域,这就是我要投射它的原因。也许可以用泛型做一些更好的事情......
      • @gabr:我已经更新了我的帖子以提出 hack #3(应该增加接口参考计数器)
      • 感谢您的所有工作,但我刚刚找到了一个非常简单的方法来解决这个问题......
      • 最后我使用了你的 hack #3 方法。如果您将自己限制在 D2009+,泛型很好,但我的代码也必须在 D2007 中工作,并且有条件地编译相同类型的泛型/非泛型版本是一团糟。
      • @gabr:如果是这样,您应该看看 System._IntfCopy 过程。如果 Dest nil,我已更新我的 AnonCopy 程序以减少“Dest”参考计数器
      【解决方案3】:

      似乎最好的方法是使用泛型在记录中存储正确类型的委托。无需破解。

      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.
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-26
        • 1970-01-01
        • 1970-01-01
        • 2010-10-15
        • 1970-01-01
        • 1970-01-01
        • 2021-06-17
        相关资源
        最近更新 更多