- PR -

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

投稿者投稿内容
がらす
ベテラン
会議室デビュー日: 2005/07/14
投稿数: 99
投稿日時: 2006-05-19 02:01
いつもお世話になっております。

イベントをリッスンする前に、2重登録を防ぐために既にどのメソッドがリッスンしているかを直接調べる方法はあるのでしょうか?

よくイベントを呼び出すときに
コード:
if(MyEvent != null)
{
    MyEvent(sender, e);
}


などとやりますが「MyEventを誰もリッスンしていないか」を確認するだけで、誰がリッスンしているかはわかりません。

今のところはリッスンするところでフラグを立てていますが、もっと良い方法があるのではないかと思っている状態です。
どうぞよろしくお願いします。
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-05-19 09:14
2重登録はこうしたら防止できるみたいです。

イベントハンドラを登録する側で。
コード:
class Class1
{
	public event EventHandler MyEvent;
}

・・・

Class1 c = new Class1();

・・・

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



面倒ですが。

_________________
囚人@わんくま同盟
囚人のジレンマな日々
_________________
囚人のジレンマな日々
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-05-19 10:45
カスタムイベントにして、add アクセサ内で value をさっ引いてから改めて追加するとか。
コード:
private EventHandler hoge;
public event EventHandler Hoge {
    add {
        hoge -= value;
        hoge += value;
    }
    remove { hoge -= value; }
}





引用:

囚人さんの書き込み (2006-05-19 09:14) より:
コード:
class Class1
{
	public event EventHandler MyEvent;
}

・・・

Class1 c = new Class1();

・・・

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




このコードは問題がありすぎるような気が。
  • MyEvent に登録されていない場合は MyEvent == null なので GetInvocationList が失敗する
  • Delegate と EventHandler を直接比較すると参照の比較になるので new したのとは常に等しくないと判断される
  • そもそも、Class1 の外からは MyEvent には += と -= しか使えないので GetInvocationList も使えない
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-05-19 11:09
引用:

MyEvent に登録されていない場合は MyEvent == null なので GetInvocationList が失敗する


お〜、null チェックが要りますね。
引用:

Delegate と EventHandler を直接比較すると参照の比較になるので new したのとは常に等しくないと判断される


Delegate の Equals がオーバーライド、等値演算子、非等値演算子がオーバーロードされているので、これは等しいと判断されます。
引用:

そもそも、Class1 の外からは MyEvent には += と -= しか使えないので GetInvocationList も使えない


いや、使えるっぽいです。
_________________
囚人のジレンマな日々
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2006-05-19 11:42
引用:

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

そもそも、Class1 の外からは MyEvent には += と -= しか使えないので GetInvocationList も使えない


いや、使えるっぽいです。


え、ほんとですか?
んなわけないと単純に思えるんですが。
※すみません、確認はしてないです。

それ以前に、この判定ではとっても変な登録のされ方してしまうと思いますが…
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-05-19 11:45
引用:

え、ほんとですか?
んなわけないと単純に思えるんですが。
※すみません、確認はしてないです。


あれ?何かやり方おかしいのかな。使えてるっぽいんですけど…。

引用:

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


と言うと?
_________________
囚人のジレンマな日々
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-05-19 11:46
引用:

Delegate の Equals がオーバーライド、等値演算子、非等値演算子がオーバーロードされているので、これは等しいと判断されます。


あ、バージョンを考慮してなかった。
.NET 1.0/1.1 ではその通りでしたが、.NET 2.0 になって等値演算子/非等値演算子の動作が変更されたようです。
比較する両者の型が異なっていた場合は、コンパイル時に警告 CS0253 が発生します。警告を無視して実行した場合、両者は参照比較となります。
引用:

Delegate.op_Equality メソッド (System)より:

2 つのデリゲートが同じ型でない場合、両者は異なるものと見なされます。

重要 :
.NET Framework Version 1.0 および 1.1 では、2 つのデリゲート間で、ターゲット、メソッド、および呼び出しリストが等しかった場合は、型が異なっていたとしても 2 つのデリゲートは等しいと見なされていました。




引用:

いや、使えるっぽいです。


ん〜? それを認めてしまったら、イベントハンドラを外部から実行可能になってしまって、イベントの前提が崩れてしまうような。
大体、その場合普通のイベントならそれで良いかも知れませんが、カスタムイベントの場合はどうするんでしょう? カスタムイベントにはイベントハンドラを返すアクセサなんか存在しませんし。
外部からイベントの GetInvocationList を取得するのはどうやっても CS0070 が発生してしまうんですが、できれば完動コードを示して頂けませんか?
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-05-19 12:02
引用:

そもそも、Class1 の外からは MyEvent には += と -= しか使えないので GetInvocationList も使えない


すいませーん(T_T)
外じゃなく、同じクラス内からやってました…。そりゃそうですよね。

引用:

.NET 1.0/1.1 ではその通りでしたが、.NET 2.0 になって等値演算子/非等値演算子の動作が変更されたようです。
比較する両者の型が異なっていた場合は、コンパイル時に警告 CS0253 が発生します。警告を無視して実行した場合、両者は参照比較となります。


なんとっ。
でも、「型が同じ」とはどういう事を指しているのでしょうか。
より、タイプセーフになったというだけで、この例ではやはり「等しい」と判断されるように思います。
引用:

重要 :
.NET Framework Version 1.0 および 1.1 では、2 つのデリゲート間で、ターゲット、メソッド、および呼び出しリストが等しかった場合は、型が異なっていたとしても 2 つのデリゲートは等しいと見なされていました。


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

_________________
囚人のジレンマな日々

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