19

受け入れられた答えが非常に不可解なままであるこの投稿にさらに:

@Button1.OnClick := pPointer(Cardinal(pPointer( procedure (sender: tObject) begin ((sender as TButton).Owner as TForm).Caption := 'Freedom to anonymous methods!' end )^ ) + $0C)^;

次のような最もシンプルでエレガントな方法を考案できるかどうか疑問に思います。

Button.OnClick :=
                    AnonProc2NotifyEvent (
                    procedure (Sender: TObject)
                    begin
                      ((Sender as TButton).Owner as TForm).Caption := 'Freedom to anonymous methods!'
                    end
                      );

同じ目的を達成するために、AnonProc2NotifyEvent は、次のシグネチャを持つ Button の所有者のメソッドです。

TOwnerOfButton = class(TForm)
  Button: TButton;
  ...
private
  ...
protected
  function AnonProc2NotifyEvent(aProc: TProc<TObject>): TNotifyEvent;
public
  ...
end;

それは実現可能ですか?もしそうなら、それを実装する方法は?

4

2 に答える 2

39

これは十分に簡単に仕事をします:

type
  TNotifyEventWrapper = class(TComponent)
  private
    FProc: TProc<TObject>;
  public
    constructor Create(Owner: TComponent; Proc: TProc<TObject>);
  published
    procedure Event(Sender: TObject);
  end;

constructor TNotifyEventWrapper.Create(Owner: TComponent; Proc: TProc<TObject>);
begin
  inherited Create(Owner);
  FProc := Proc;
end;

procedure TNotifyEventWrapper.Event(Sender: TObject);
begin
  FProc(Sender);
end;

function AnonProc2NotifyEvent(Owner: TComponent; Proc: TProc<TObject>): TNotifyEvent;
begin
  Result := TNotifyEventWrapper.Create(Owner, Proc).Event;
end;

Ownerパラメータ inAnonProc2NotifyEventは、ラッパー オブジェクトの有効期間を管理できるようにするためのものです。そのようなものがないと、のインスタンスがリークしますTNotifyEventWrapper

Ownerイベントを接続するコンポーネントをとして渡します。例えば:

Button1.OnClick := AnonProc2NotifyEvent(
  Button1,
  procedure(Sender: TObject)
  begin
    (Sender as TButton).Caption := 'Clicked';
  end
);

そのため、ボタンが破棄されると、TNotifyEventWrapperも破棄されます。ラッパー オブジェクトは、関連付けられているイベントを持つオブジェクトと少なくとも同じくらい存続する必要があります。したがって、Button1所有者としての選択は当然のことであり、当然のことです。

于 2012-07-15T12:11:19.013 に答える
5

これを参照するために、上記の以前の SO 投稿で参照されているBarry Kellyのブログ投稿を調べて、この解決策を思いつきました。

function TMainForm.Proc2NotifyEvent(const aProc: TNotifyReference): TNotifyEvent;
type
  TVtable = array[0..3] of Pointer;
  PVtable = ^TVtable;
  PPVtable = ^PVtable;
begin
  TMethod(Result).Code := PPVtable((@aProc)^)^^[3];
  TMethod(Result).Data := Pointer((@aProc)^);
end;

まだ暗号化されていますが、カプセル化されているため、最初の方法と比較してコーダーの作業が楽になります。

MethRefToMethPtrMakeNotifyを整理して、すべてを 1 つのメソッドにまとめようとしました。

メソッドのシグネチャに (わずかな) 変更があり、引数aProcconstになったことに注意してください。

于 2012-07-15T14:00:10.547 に答える