- PR -

イベントをリッスンしている関数を知る方法

投稿者投稿内容
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-05-19 12:20
引用:

囚人さんの書き込み (2006-05-19 12:02) より:
でも、「型が同じ」とはどういう事を指しているのでしょうか。
より、タイプセーフになったというだけで、この例ではやはり「等しい」と判断されるように思います。

引用:

つまり、.NET Framework 2.0 では、「2つのデリゲート間で、ターゲット、メソッド、呼び出しリスト、及びデリゲートの型が等しい場合」と読み取れます。



こういうことです。
コード:
private static void Hoge(object sender, EventArgs e) {}

public static void Main() {
    EventHandler handler = new EventHandler(Hoge);
    Delegate same = handler;
    Delegate another = new EventHandler(Hoge);
    Console.WriteLine(handler == same);        // true
    Console.WriteLine(handler == another);     // false
    Console.WriteLine(handler.Equals(another));// true
}

囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-05-19 12:48
なるほど。
今 .NET2.0 環境が試せないのでアレなんですが、先程 Hongliang さんが出されたリンクには、
引用:

同じターゲット、メソッド、および呼び出しリストを共有する、同じ型の 2 つのデリゲートが等しいと見なされます。
2 つのデリゲートが同じ型でない場合、両者は異なるものと見なされます。

メソッドと比較対象が等しいかどうかを次のように比較します。
比較する 2 つのメソッドがどちらも静的メソッドであり、同じクラスの同じメソッドである場合、その 2 つのメソッドは等しいと見なされ、比較対象も等しいと見なされます。
比較する 2 つのメソッドがどちらもインスタンス メソッドであり、同じオブジェクトの同じメソッドである場合、その 2 つのメソッドは等しいと見なされ、比較対象も等しいと見なされます。
それ以外の場合、メソッドは等しいとは見なされず、比較対象も等しいとは見なされません。
2 つの呼び出しリストの要素の順序が同じで、2 つのリストの対応する要素が同じメソッドとターゲットを表している場合、2 つの呼び出しリストは同じと見なされます。


とあります。
コード:

private static void Hoge(object sender, EventArgs e) {}

public static void Main() {
EventHandler handler = new EventHandler(Hoge);
Delegate same = handler;
Delegate another = new EventHandler(Hoge);
Console.WriteLine(handler == same); // true
Console.WriteLine(handler == another); // false
Console.WriteLine(handler.Equals(another));// true
}


これは、もはや等値演算子はオーバーロードされていない事と同義という事でしょうか。
もしくは、インスタンスの型ではなく、参照の型で判断している事でしょうか。
どうも、リファレンスの説明と違う気がするのですが。

コード:

private static void Hoge(object sender, EventArgs e) {}

public static void Main() {
EventHandler handler = new EventHandler(Hoge);
Delegate same = handler;
EventHandler another = new EventHandler(Hoge);
Console.WriteLine(handler == same); // true
Console.WriteLine(handler == another); // true
Console.WriteLine(handler.Equals(another));// true
}


こうすると、こうなるのでしょうか。

質問の本題に戻りますが、Hongliang さんのカスタムイベントの例を見て思いつきました。カスタムじゃあないイベントでも
コード:

c.MyEvent -= new EventHandler(c_MyEvent);
c.MyEvent += new EventHandler(c_MyEvent);


毎回こうすれば、2重登録を防止できるかな。
でも、「デリゲートが等しい」という概念をもう少し詰める必要があるかもしれません。
そうでないと、削除したり追加したりするのが毎回別物と判断されてしまいます。(私はそうならないと思っていますが)

_________________
囚人@わんくま同盟
囚人のジレンマな日々

[ メッセージ編集済み 編集者: 囚人 編集日時 2006-05-19 12:50 ]
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-05-19 13:00
さらに詰めます。
.NET 1.x 環境では、
コード:
public delegate void MyDelegate1();
public delegate void MyDelegate2();

class Program
{
	public static void Hoge(){}

	static void Main(string[] args)
	{
		Console.WriteLine(new MyDelegate1(Hoge) == new MyDelegate1(Hoge)); // true
		Console.WriteLine(new MyDelegate2(Hoge) == new MyDelegate2(Hoge)); // true
		Console.WriteLine(new MyDelegate1(Hoge) == new MyDelegate2(Hoge)); // true
	}
}


こうなります。
これが .NET2.0 環境では、3つ目は false になるよ、という事ではないでしょうか。(.NET 1.x では 3 番目が true になるなんて、初めて気付いたわけですが^^;)
_________________
囚人のジレンマな日々
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-05-19 13:47
引用:

これは、もはや等値演算子はオーバーロードされていない事と同義という事でしょうか。
もしくは、インスタンスの型ではなく、参照の型で判断している事でしょうか。
どうも、リファレンスの説明と違う気がするのですが。


等値演算子のオーバーロードはされています。
new EventHandler(Hoge) == new EventHandler(Hoge)
は true を返しますから。
どうやら、Delegate 型と実際の delegate で宣言された型の間の比較については、コンパイラが op_Equality を呼び出さずに単純に ceq で比較するようになっているのが原因のようです。これは C# コンパイラ特有の挙動のようで、VB では普通に op_Equality を呼び出しています。


引用:

質問の本題に戻りますが、Hongliang さんのカスタムイベントの例を見て思いつきました。カスタムじゃあないイベントでも
コード:
c.MyEvent -= new EventHandler(c_MyEvent);
c.MyEvent += new EventHandler(c_MyEvent);


毎回こうすれば、2重登録を防止できるかな。


ああ、確かに。

引用:

.NET 1.x 環境では、
コード:
public delegate void MyDelegate1();
public delegate void MyDelegate2();

class Program
{
	public static void Hoge(){}

	static void Main(string[] args)
	{
		Console.WriteLine(new MyDelegate1(Hoge) == new MyDelegate1(Hoge)); // true
		Console.WriteLine(new MyDelegate2(Hoge) == new MyDelegate2(Hoge)); // true
		Console.WriteLine(new MyDelegate1(Hoge) == new MyDelegate2(Hoge)); // true
	}
}


こうなります。
これが .NET2.0 環境では、3つ目は false になるよ、という事ではないでしょうか。(.NET 1.x では 3 番目が true になるなんて、初めて気付いたわけですが^^;)


これは私も知りませんでした……。
.NET 2.0 ではそもそもこの三番目はコンパイル時にエラー CS0019 が出ますね。これは真っ当な変更でしょう。
// VB では等値演算子による比較が可能みたいですが。
MSDN の記述は確かにこの問題について書かれているようです。勘違いしていました。
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-05-19 13:56
引用:

.NET 2.0 ではそもそもこの三番目はコンパイル時にエラー CS0019 が出ますね。これは真っ当な変更でしょう。


これは納得いく変更ですね。

引用:

等値演算子のオーバーロードはされています。
new EventHandler(Hoge) == new EventHandler(Hoge)
は true を返しますから。
どうやら、Delegate 型と実際の delegate で宣言された型の間の比較については、コンパイラが op_Equality を呼び出さずに単純に ceq で比較するようになっているのが原因のようです。これは C# コンパイラ特有の挙動のようで、VB では普通に op_Equality を呼び出しています。


これは…。何かバグに近いと思ってしまいますね。
_________________
囚人のジレンマな日々
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2006-05-19 19:59
引用:

囚人さんの書き込み (2006-05-19 11:45) より:
引用:

それ以前に、この判定ではとっても変な登録のされ方してしまうと思いますが…


と言うと?


いや、

コード:
foreach(Delegate d in c.MyEvent.GetInvocationList())
{
	if(d != new EventHandler(c_MyEvent))
	{
		c.MyEvent += new EventHandler(c_MyEvent);
	}
}


現在登録されてる(c_MyEvent以外の)イベントハンドラの個数分
c_MyEventのハンドラが登録されてしまいませんか?
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-05-19 22:33
引用:

現在登録されてる(c_MyEvent以外の)イベントハンドラの個数分
c_MyEventのハンドラが登録されてしまいませんか?


あ、めちゃめちゃですね^^;
_________________
囚人のジレンマな日々

スキルアップ/キャリアアップ(JOB@IT)