イベントハンドラーでクロージャーを使用しようとすると、コンパイラーは次のように文句を言います:
互換性のない型: 「メソッド ポインタと通常のプロシージャ」
私は理解しています..しかし、メソッドポインターでクローザーを使用する方法はありますか? できるかどうかを定義する方法は?
例:
Button1.Onclick = procedure( sender : tobject ) begin ... end;
ありがとう!
イベントハンドラーでクロージャーを使用しようとすると、コンパイラーは次のように文句を言います:
互換性のない型: 「メソッド ポインタと通常のプロシージャ」
私は理解しています..しかし、メソッドポインターでクローザーを使用する方法はありますか? できるかどうかを定義する方法は?
例:
Button1.Onclick = procedure( sender : tobject ) begin ... end;
ありがとう!
@Button1.OnClick := pPointer(Cardinal(pPointer( procedure (sender: tObject)
begin
((sender as TButton).Owner as TForm).Caption := 'Freedom to anonymous methods!'
end )^ ) + $0C)^;
Delphi 2010で動作します
素晴らしい質問です。
私の知る限り、現在のバージョンの Delphi では実行できません。オブジェクトのイベント ハンドラーをすばやくセットアップするためにこれらの匿名プロシージャがあれば、たとえば、xUnit の種類の自動テスト フレームワークでテスト フィクスチャをセットアップする場合に便利なので、これは非常に残念です。
CodeGear がこの機能を実装するには、次の 2 つの方法があります。
1: 匿名メソッドの作成を許可します。このようなもの:
Button1.OnClick := procedure( sender : tobject ) of object begin
...
end;
ここで問題となるのは、無名メソッドの自己ポインタを何にするかです。匿名メソッドが作成されたオブジェクトの自己ポインターを使用することもできますが、その場合、オブジェクト コンテキストからのみ匿名メソッドを作成できます。より良いアイデアは、舞台裏でダミー オブジェクトを作成して匿名メソッドを含めることです。
2: 別の方法として、定義されたシグネチャを共有する限り、イベント タイプがメソッドとプロシージャの両方を受け入れることができるようにすることもできます。そのようにして、必要な方法でイベント ハンドラーを作成できます。
Button1.OnClick := procedure( sender : tobject ) begin
...
end;
私の目には、これが最善の解決策です。
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;
上記が実際にコンパイルされるかどうかはわかりませんが、一般的なアイデアが得られるはずです。以前にこれを行ったことがありますが、通常の手順で機能しました。コンパイラーがクロージャーに対して生成するコードがわからないため、これがクロージャーに対して機能するかどうかはわかりません。
以下を拡張して、より多くのフォームイベントタイプを処理するのは簡単です。
使用法
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.