- PR -

デリゲートとイベントについて

投稿者投稿内容
へるまろ
ベテラン
会議室デビュー日: 2003/02/04
投稿数: 57
お住まい・勤務地: 東京
投稿日時: 2003-02-04 23:09
失礼しました。

先走るあまり"おおぽか"をしてしまいました。
申し訳ありません。
一郎
ぬし
会議室デビュー日: 2002/10/11
投稿数: 1081
投稿日時: 2003-02-05 10:01
>虎吉さん
>ここが盲点だった気がします。
>デリゲートはクラスであるというのは良く見ましたが・・・

デリゲートはクラスではなく、型(Type)ですね。
それに、盲点だったんですか?私は、虎吉さんは「デリゲート型のフィールドデリゲート型のイベントが同じように動いて、使い分け方が分からない」と言っていると思っていたんですが。
dlgTestHandlerとeの違いではなく、dとeの違いの話をしているんですよね?


>NothingBut.NETFXさん
>dはFieldDefとして、eはEventDefとして、それぞれメタデータに書き込まれています。
>dはVB.NETから見てイベントに見えないため、イベント用に用意された便利な機能が使えず、両者の機能は明らかに異なるように見えるのです。

なるほど、つまり.NETでは、イベントというメンバを持つことを可能にすることによって、何か起きたときに他に伝えるという概念を、表現しやすくしたということですかね。
(実際イベントって良く使うし)
一郎
ぬし
会議室デビュー日: 2002/10/11
投稿数: 1081
投稿日時: 2003-02-06 10:44
引用:
パダワンさん
>登録されたイベントやデリゲードは、それらと同じクラス内からでしか呼び出すことができないので


始めはさらっとこの部分を読み流していましたが、実際にデリゲート型のフィールドとデリゲート型のイベントを作って色々操作してると、決定的な違いを見つけました。

それは、「イベントは、それをメンバとするクラス以外からは起動できない」ということです。
(そんなもん前から知ってるよ、とか言われそうですが)
外から関数(メソッド)を登録するためにはもちろんpublicでなければいけませんが、publicだからといって外から好き勝手にイベントを起動されるようなことがあってはなりません。ここから見ても、イベントは「オブジェクト内で変化等があったときに呼び出して欲しいメソッドを登録しておけ」という意味合いのものなんでしょうね。
デリゲート型のフィールドは外からでも起動(そのフィールドが指しているメソッドを呼び出すこと)ができました。
パダワン
会議室デビュー日: 2002/07/27
投稿数: 15
投稿日時: 2003-02-06 12:27
>デリゲート型のフィールドは
>外からでも
>起動(そのフィールドが指しているメソッドを呼び出すこと)ができました。

私も今
コードを打って確認しました。

デリゲードの場合
デリゲードフィールドを使ってデリゲードを登録したクラスの
そのフィールドを使えば
デリゲードを登録していない他のクラスからでも起動可能ですね。
NothingButXMLInfoSet
大ベテラン
会議室デビュー日: 2002/07/16
投稿数: 116
投稿日時: 2003-02-06 19:27
引用:

>>デリゲートはクラスであるというのは良く見ましたが・・・
デリゲートはクラスではなく、型(Type)ですね。


デリゲートはILレベルではクラスです。コンパイラが展開してくれます。虎吉さんがおっしゃっているのはそのことだと思います。ですから、「型」というのも正しいですし、「クラス」というのも正しいでしょう。

引用:

それは、「イベントは、それをメンバとするクラス以外からは起動できない」ということです。
((略))
publicだからといって外から好き勝手にイベントを起動されるようなことがあってはなりません。


それでは次のようなC#のコードはどう説明すればいいでしょうか。

コード:
using System;
class App {
    static void Main() {
        B b = new B();
    }
}

class A {
    internal EventHandler ee;
    internal event EventHandler e {
        add { ee = value; }
        remove { ee = null; }
    }
}

class B {
    internal B() {
        A a = new A();
        a.e+= new EventHandler(MyE);
        a.ee(this, EventArgs.Empty);
    }
    private void MyE(object s, EventArgs e) {
        Console.WriteLine("イベント発生");
    }
}


eはイベントです。eに登録したものが外部から呼び出されて、結果としてeイベントが発生したことになっています。

わざと変なコードを書いているかのように思われるかもしれませんが、結局のところC#コンパイラが行うのは「internal EventHandler f;」というコードを、次のように展開することです。これは、add/removeアクセッサを書かないものぐさな私たちのためにデフォルト実装を提供するという親切心でしかありません。

コード:
private EventHandler f;
internal void add_f(EventHandler value) { this.f += value; }
internal void remove_f(EventHandler value) { this.f -= value; }


お分かりのように、デフォルトの展開方式では「+=(AddHandler)」で設定されたイベントハンドラを格納するフィールドがprivateに宣言されるため、外部からこのデリゲート型のフィールドにアクセスできなくなり、外部から起動できないように見えるだけです。

上記のように自分でadd/removeアクセッサを定義する場合は、格納するフィールドも自分で定義しなければなりません。自分で定義するので、privateにしなければならないわけでもありません。ニーズに応じたアクセス修飾子を付けることができます。

イベントというのは、クラスの内部ではフィールドと2つのアクセッサメソッドの対でしかありません。ちょうどプロパティが2つのアクセッサメソッドの対でしかないのと同じです。

そういうわけですから、私はイベントそのものに

引用:

ここから見ても、イベントは「オブジェクト内で変化等があったときに呼び出して欲しいメソッドを登録しておけ」という意味合いのものなんでしょうね。


というようなセマンティクスはないと思っています。もっとも、ある種の設計パターン(ベストプラクティス?)として、イベントをそのように扱うべきだ、という議論であればそういうパターンを定義すること自体に反対ではありません。
一郎
ぬし
会議室デビュー日: 2002/10/11
投稿数: 1081
投稿日時: 2003-02-07 09:45
引用:
デリゲートはILレベルではクラスです。


アセンブリを見てみましたが、確かに「System.MulticastDelegateを拡張したクラスだ」みたいに書いてありました。
でもそうすると、構造体も列挙型も全部クラスということで、プログラマのコミュニケーションには不都合ですね。
「クラスのさぁ・・・」
「クラス?どんな。」
「System.ValueTypeもSystem.EnumもSystem.MulticastDelegateも親クラスとして持っていないクラスのさぁ・・・」
みたいな。

引用:
これは、add/removeアクセッサを書かないものぐさな私たちのためにデフォルト実装を提供するという親切心


アクセッサを定義しないイベントを定義すると、privateなデリゲート型フィールドとaddアクセッサ、removeアクセッサが作られるんですね。
確かに私はものぐさですが、良く使われる形の実装をデフォルトで提供するというこなんでしょう。

一段と.NETの理解が深まりました。これは勉強になりました。
ありがとうございました。
ナキヲ
常連さん
会議室デビュー日: 2003/08/22
投稿数: 32
お住まい・勤務地: 京都・自宅から勤務地まで自転車で40分
投稿日時: 2003-12-01 14:33
イベントとデリゲートの違いについて
調べていてこのスレッドにたどり着きました。
このスレッドでいわれている”イベント”は
"event"キーワード付きで宣言されたもののことだと思うのですが、そうすると、
以下の

引用:

class A {
internal EventHandler ee;
internal event EventHandler e {
add { ee = value; }
remove { ee = null; }
}
}



は"event"キーワード付きで宣言されたイベントの説明補足
としては少し違うような気がしました。

コンパイラが展開するコードの内容については
非常に参考になりました。


[ メッセージ編集済み 編集者: ナキヲ 編集日時 2003-12-01 14:34 ]
ナキヲ
常連さん
会議室デビュー日: 2003/08/22
投稿数: 32
お住まい・勤務地: 京都・自宅から勤務地まで自転車で40分
投稿日時: 2003-12-01 14:45
おっと、
add/removeの使用はevent独自のものなんですね。。
(今ドキュメント見て知りました)
失礼しました。

いずれにしてもeventキーワードのついたデリゲートは
標準で
・eventが定義されたクラスからしか起動できない
・+/−で、使用側が知っているハンドラの追加、登録しか
 できない。
ということですね。

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