2016-10-26 14 views
17

ハンドラがメソッドリファレンスであるイベントハンドラのリストを作成しようとしています。 特定のハンドラを削除するには、リスト内で特定する必要があります。 しかし、2つのメソッド参照のコードアドレスを比較するにはどうすればよいですか?2つのメソッド参照が同じメソッドを参照しているかどうかを確認する方法?

type 
    TEventHandler = reference to procedure; 

procedure TestProc; 
begin 
end; 

procedure TForm26.FormCreate(Sender: TObject); 
var 
    Handlers: TList<TEventHandler>; 
begin 
    Handlers := TList<TEventHandler>.create; 
    try 
    Handlers.Add(TestProc); 
    Handlers.Remove(TestProc); { doesn't work } 
    Assert(Handlers.Count=0); { fails } 
    Assert(Handlers.IndexOf(TestProc)>=0); { fails } 
    finally 
    FreeAndNil(Handlers); 
    end; 
end; 

TList <のデフォルト比較者は、メソッド参照を適切に比較しません。 どうすれば比較できますか? TMethodに似た構造がありますが、メソッド参照にはありますか?

+0

TEqualityComparer .Default.Equals(A、B) –

+0

そして、あなた自身の宣言の代わりにTProcを使うことができます... System.SysUtilsを追加するだけです。 –

+0

@ZENs私はTProcについて知っているので、私はできるだけ明確な例を作りようとしました。 TEqualityComparer .Default.Equals(A、B)は機能しません。私はそれをテストしました(そうでなければTList <>。Removeも動作します、デフォルトのcomparerに基づいています)。 –

答えて

15

これは、それほど簡単ではありません。

なぜこのようなことが起こるのかを理解するには、コンパイラがメソッド参照をどのように割り当てるかを理解する必要があります。

あなたが書いたコードは、基本的には、コンパイラによって、このに翻訳されています

Handlers.Add(procedure begin TestProc; end); 
Handlers.Remove(procedure begin TestProc; end); 

は、今、私たちは、あなたが同じルーチン内の複数の匿名メソッドを持っている場合、彼らが実際にあることを別の匿名メソッドを知っていても自分の場合コードは同一です。体内コード場合でも、その周りにハッキングして決定するバイナリコードの解析を必要とするであろう -

How are anonymous methods implemented under the hood?を参照)これは、自分の体のコードが同じであってもAddRemoveに渡された値が異なることを意味します同じです。

、あなたは唯一の匿名メソッドを持っているので、それがうまくいく次のようにコードを変更希望の場合 - このために、それは動作しますが、通常は、あなたが日常まったく同じ内の追加と削除ではないでしょう切り取ら:

var 
    Handlers: TList<TEventHandler>; 
    Handler: TEventHandler; 
begin 
    Handlers := TList<TEventHandler>.create; 
    try 
    Handler := TestProc; 
    Handlers.Add(Handler); 
    Handlers.Remove(Handler); 
    Assert(Handlers.Count=0); 
    finally 
    FreeAndNil(Handlers); 
    end; 
end; 

あなたは私の個人的な勧告は、匿名メソッドの種類と使用手順や方法を避けるために、あるイベントハンドラを追加および削除リストする場合:

type 
    TEventHandlerA = procedure; 
    TEventHandlerB = procedure of object; 

をあなたのコードを知っているので、1が優れているの決定はあなた次第ですより良い。

+0

私はパラメータとしてメソッド参照を使って何かを呼び出すと、匿名メソッドが生成されることは期待していませんでした。私は実際には匿名メソッドなしでメソッド参照を使用できると思います。ありがとうございました! –

+1

@AndreiGalatyn:匿名メソッドを使わずに 'procedure of object'参照を使うことはできますが、後者**は** anonmeth referencesであるため、'参照参照 '参照は使用できません。 –

関連する問題