2010-02-21 58 views
5

以下代碼(僅用於演示此問題)編譯並在Delphi 2010中運行。在Delphi 2009中,編譯器因「E2035實際參數不足」而失敗。在Delphi 2009中投射匿名程序

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。鑄造用於特定匿名PROC存儲到這個領域]

回答

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(應該增加裁判計數器,這個想法是從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. 
+0

它適用於測試案例,但不適用於我的(稍微複雜的)案例。接口引用計數出現問題。我會盡量整理一個更準確的測試用例。 TProc只是不同的'參考程序'實體的存儲區域,這就是爲什麼我要投它。也許更好的東西可以用泛型... – gabr 2010-02-22 07:01:49

+0

@gabr:我已經更新了我的帖子,建議破解#3(應該增加界面ref counter) – kludg 2010-02-22 08:21:13

+0

感謝您的所有工作,但我剛剛找到了一種非常簡單的方法解決這個問題... – gabr 2010-02-22 08:42:51

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 and curiouser。

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.