以下代码(仅用于演示问题)构建并在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存储到此字段中。]
答案 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.