2008-12-11 41 views

回答

10
@Button1.OnClick := pPointer(Cardinal(pPointer(procedure (sender: tObject) 
begin 
    ((sender as TButton).Owner as TForm).Caption := 'Freedom to anonymous methods!' 

end)^) + $0C)^; 

德爾福2010年works

5

一個很好的問題。

據我所知,目前版本的Delphi中無法做到這一點。這非常不幸,因爲這些匿名過程對於快速設置對象的事件處理程序非常有用,例如在xUnit自動測試框架中設置測試夾具時。

應該有兩種方式CodeGear的實現此功能:

1:允許創建的匿名方法。就像這樣:

Button1.OnClick := procedure(sender : tobject) of object begin 
    ... 
end; 

這裏的問題是作爲匿名方法的自指針。可以使用創建匿名方法的對象的自指針,但只能從對象上下文創建匿名方法。一個更好的主意可能是在幕後創建一個虛擬對象來包含匿名方法。

2或者,可以允許事件類型接受這兩種方法和過程,只要它們共享定義的簽名即可。這樣,你就可以創建事件處理程序你想要的方式:

Button1.OnClick := procedure(sender : tobject) begin 
    ... 
end; 

在我的眼裏,這是最好的解決方案。

+0

的方法不具有相同的調用簽名具有相同參數的過程。方法總是將Self作爲「隱藏」參數傳遞。 – 2008-12-25 17:48:42

+1

是的,當然。但我看不出爲什麼編譯器不應該能夠在「幕後」處理這兩種情況。例如,如果需要一個方法,它可以在匿名過程周圍創建一個虛擬類包裝。 – 2009-02-03 08:29:46

+1

這種模式在JavaScript Python等動態語言中非常常見。 – 2013-10-22 08:41:27

4

在以前的Delphi版本中,你可以通過添加隱藏自我指針參數使用常規的程序,事件處理程序和硬盤類型轉換它:

procedure MyFakeMethod(_self: pointer; _Sender: TObject); 
begin 
    // do not access _self here! It is not valid 
    ... 
end; 

... 

var 
    Meth: TMethod; 
begin 
    Meth.Data := nil; 
    Meth.Code := @MyFakeMethod; 
    Button1.OnClick := TNotifyEvent(Meth); 
end; 

我不知道上面的真編譯,但它應該給你的一般想法。我之前已經完成了這個工作,並且它爲常規程序工作。由於我不知道編譯器爲閉包生成了什麼代碼,我不能說這是否適用於它們。

1

它易於擴展以下處理更多形式的事件類型。

使用

procedure TForm36.Button2Click(Sender: TObject); 
var 
    Win: TForm; 
begin 
    Win:= TForm.Create(Self); 
    Win.OnClick:= TEventComponent.NotifyEvent(Win, procedure begin ShowMessage('Hello'); Win.Free; end); 
    Win.Show; 
end; 

代碼

unit AnonEvents; 

interface 
uses 
    SysUtils, Classes; 

type 
    TEventComponent = class(TComponent) 
    protected 
    FAnon: TProc; 
    procedure Notify(Sender: TObject); 
    class function MakeComponent(const AOwner: TComponent; const AProc: TProc): TEventComponent; 
    public 
    class function NotifyEvent(const AOwner: TComponent; const AProc: TProc): TNotifyEvent; 
    end; 

implementation 

{ TEventComponent } 

class function TEventComponent.MakeComponent(const AOwner: TComponent; 
    const AProc: TProc): TEventComponent; 
begin 
    Result:= TEventComponent.Create(AOwner); 
    Result.FAnon:= AProc; 
end; 

procedure TEventComponent.Notify(Sender: TObject); 
begin 
    FAnon(); 
end; 

class function TEventComponent.NotifyEvent(const AOwner: TComponent; 
    const AProc: TProc): TNotifyEvent; 
begin 
    Result:= MakeComponent(AOwner, AProc).Notify; 
end; 

end. 
相關問題