在Delphi 2009中投射匿名程序

时间:2010-02-21 20:00:57

标签: delphi delphi-2009 anonymous-methods

以下代码(仅用于演示问题)构建并在Delphi 2010中工作。在Delphi 2009中,编译器失败并显示“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绝对b)。有没有人知道这个编译器缺陷的更好的解决方法?

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

3 个答案:

答案 0 :(得分:2)

诀窍是不做

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

Curiouser和curiouser。

答案 1 :(得分:1)

我找到了一个黑客#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(应该增加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.

答案 2 :(得分:1)

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

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.