- 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のハンドラが登録されてしまいませんか?
|
あ、めちゃめちゃですね^^;
_________________ 囚人のジレンマな日々
|