• ベストアンサー

Visual-C#の event キーワードの「意義」が分かりません

Visual-C#というものを初めて触っている者です。 フォーム上にボタン等のコントロールを配置して、ボタンをダブルクリックすると、イベントハンドラをユーザが記述するコード部分(partial class)が表示されてくるのですが(Form1.cs)、このpartial classの残りの、ユーザが編集する必要のないコードはForm1.Designer.cs内に自動生成されます。 このForm1.Designer.cs内に、たとえば this.Button1.Click += new System.EventHandler( this.Button1_Click );  ←(1) のようなコードが自動生成されているわけです。 ここで、Button1とはButtonクラスのオブジェクトであり、ClickとはButtonクラスの(Controlクラスから継承した)Clickイベントだということです。 http://msdn.microsoft.com/ja-jp/library/system.windows.forms.control.click(VS.85).aspx public event EventHandler Click  ←(2) ここで使用されているEventHandlerとは何かというと、delegateです。 http://msdn.microsoft.com/ja-jp/library/system.eventhandler.aspx public delegate void EventHandler(Object sender, EventArgs e)  ←(3) 「イベントとは、コンピュータ・プログラムの実行に際し、何らかのアクションが発生した際にプログラムに発信される信号(これをメッセージと呼んだりする)をいう。」(『ウィキペディア(Wikipedia)』) この「イベント」を、.NetFrameworkのクラスライブラリでは、(2)のように「EventHandler」という名前のデリゲートクラス型の変数として定義しているわけですが、(2)の中の「event」というキーワードの「意義」が分かりません。 Controlクラス定義内で(2)式のように、コントロールの「クリック」イベントを、「EventHandler」という名前のデリゲートクラス型の変数と定義するというのなら、それはそれで分かるのですが、なぜ更に「event」というキーワードを付ける必要があるのかが、よく分からないのです。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.4

> と書いた上での話なので、ClickイベントがButtonクラスのメンバであるという認識はいちおう持ってはいます。 ってことは,「メンバとは何か」の認識の問題でしょうか。 > 「の「イベント」を、.NetFrameworkのクラスライブラリでは、(2)のように「EventHandler」という名前のデリゲートクラス型のメンバ変数として定義しているわけですが、」 > と書いておくべきでした。 「変数」を「メンバ変数」と置き換えたところで,間違っていることに違いはありません。 メンバというのは, ・フィールド ・(配列型の場合,配列の)要素 ・メソッド ・プロパティ ・イベント です。イベントは独立のカテゴリです。 ref) ECMA-335 / 5 Terms and definitions MSDNに資料が見つかったので断言してしまいますが,イベントとは, ObserverパターンにおけるObserverインターフェイスをデリゲートで置き換えた物です。 Wikipediaの表現は気にせず,そういうものだと考えた方がよいと思います。 なお,こちらは資料が見つかっていないのですが, デリゲートの定義は,そういうシグネチャを持つ型の定義だと認識した方がよいです。 デリゲートは確かにクラスですが,ほとんどの場合「メソッド型」だと考えた方がしっくりきます。 System.EventHandlerは,イベントハンドラで利用するメソッドの型を定義していると考えます。 C# 2.0からはイベントへの追加・削除時にデリゲート型をnewするコードを省略できるようになったので, よりそちらの考え方をするとコードがよみやすくなります。 Button1.Click += Button1_Click; // C# 2.0からの省略表記

参考URL:
http://msdn.microsoft.com/en-us/library/ms954621.aspx
mha01
質問者

お礼

http://msdn.microsoft.com/ja-jp/library/ms173118.aspx 「フィールドとは、クラスまたは構造体で直接宣言される任意の型の変数です。フィールドは、それを含んでいる型のメンバです。」 と書いてあるのですが、フィールドをメンバ変数と呼ぶのはまずいのでしょうか? http://www.java2s.com/Tutorial/CSharp/0140__Class/0100__Member-Variable.htm にも、 7. 5. Member Variable 7. 5. 1. fields とか書いてあるし、Member Variableの日本語訳は「メンバ変数」ではないのでしょうか? >MSDNに資料が見つかったので断言してしまいますが,イベントとは, >ObserverパターンにおけるObserverインターフェイスをデリゲートで置き換えた物です。 「Controlクラス定義内で(2)式のように、コントロールの「クリック」イベントを、「EventHandler」という名前のデリゲートクラス型の変数と定義するというのなら、それはそれで分かるのですが、」 と初めから書いてあります。

mha01
質問者

補足

>メンバというのは, >・フィールド ・・・ >・イベント >です。イベントは独立のカテゴリです。 仰っている意味が分かりました。 私はフィールドとイベントをいっしょくたにして考えていました。 すいません。

すると、全ての回答が全文表示されます。

その他の回答 (3)

回答No.3

eventはCLIのイベント機構を利用するためのキーワードです。 > この「イベント」を、.NetFrameworkのクラスライブラリでは、(2)のように「EventHandler」という名前のデリゲートクラス型の変数として定義しているわけですが、 違います。 EMCA-335 Common Language Infrastructure(CLI) 4th Editionの5 Temrs and definitionsに定義があります。 > event: A member that enables an object or class to provide notifications イベントとは,あくまでメンバです。 さらに言うと,CLIの実行環境によって支援される,特殊なメソッドになります (8.11.4)。 # 個人的には,CLIによる簡易Observerパターン実装のサポートだと思っています。 そして,例えばSystem.Windows.Forms.Controls.Clickイベントのイベントハンドラの型がSystem.EventHandlerになります。

参考URL:
http://www.ecma-international.org/publications/standards/Ecma-335.htm
mha01
質問者

お礼

回答ありがとうございます。 「ここで、Button1とはButtonクラスのオブジェクトであり、ClickとはButtonクラスの(Controlクラスから継承した)Clickイベントだということです。」 と書いた上での話なので、ClickイベントがButtonクラスのメンバであるという認識はいちおう持ってはいます。 「の「イベント」を、.NetFrameworkのクラスライブラリでは、(2)のように「EventHandler」という名前のデリゲートクラス型の変数として定義しているわけですが、」 → 「の「イベント」を、.NetFrameworkのクラスライブラリでは、(2)のように「EventHandler」という名前のデリゲートクラス型のメンバ変数として定義しているわけですが、」 と書いておくべきでした。 >さらに言うと,CLIの実行環境によって支援される,特殊なメソッドになります (8.11.4)。 #1さんが紹介してくれたサイト内で、 「event は、デリゲートに対するプロパティのようなもの」 という解説があったので、何と言うか、いちおう、そういうプロパティ的な意味でのメソッドであるという認識はあります。 The CTS supports events in precisely the same way that it supports properties.

mha01
質問者

補足

 #1さんの紹介サイトと#3さんのご意見に触発されて、抽象化された信号としての「イベント」と、クラスのメンバとしての『イベント』と、イベントハンドラが、.NET Framework上でどのような関係になっているのかいろいろと調べてみて、自分なりに整理してみましたところ、Observerパターンを実装する場合のIObserverインターフェイスやIObservableインターフェイスが、実体を持たない単なるインターフェイスに過ぎないのに対して、デリゲートとしての『イベント』は、コンピュータ上に明確な実体を持つオブジェクトであるという認識が得られました。 (デリゲートがオブジェクトであるという「知識」は初めから有りましたが、デリゲートもまた、他のオブジェクトと同様に、コンピュータのメモリ空間上に明確に存在し、他のオブジェクトとお互いにメッセージをやりとりしながら、生き生きと動いている存在であるというイメージが、頭の中に浮かび上がってきました。) (1)クラスのメンバとしての『イベント』は、抽象化された信号としての「イベント」を受け取るためのデリゲート型オブジェクト(event receiver)である。 (1)名前空間Systemにおいて、EventHandlerクラス(デリゲートクラス)が次のように定義されている。   public delegate void EventHandler( object sender, EventArgs e);  このEventHandler型オブジェクトの役目は、オブジェクトsenderと、EventArgsオブジェクトeの二つを、同じシグネチャを持つ「イベントハンドラ」(処理ブロックの付いたメソッド)に、アーギュメントとして渡す事である。 (2)名前空間System.Windows.Formsにおいて、全てのコントロールの基底クラスとなるControlクラスが定義されており、そのメンバとして、"Click"という名称の『イベント』(これは、そのコントロールがクリックされたという「イベント」を受け取るための、event receiverとしての、インスタンス変数)が次のように宣言されている。   public event EventHandler Click; (3)ButtonクラスはControlクラスの派生クラスなので、メンバ『イベント』"Click"を継承する。 そこで、メンバ『イベント』"Click"に、Buttonオブジェクト button1 がクリックされたという「イベント」が起きたときに実行すべき処理を記述した「イベントハンドラ」(処理ブロックの付いたメソッド)の参照を登録することが出来る。  this.button1.Click += new System.EventHandler( this.button1_Click );   (4)このようにすると、オブジェクトbutton1が持つ(has-a関係)デリゲート型メンバオブジェクト"button1.Click"は、そのオブジェクトがクリックされたという「イベント」が発生するのを監視する、UIベッタリでもSubjectベッタリでも無い、独立したObserverとして、その役目を果たすと考えることが出来る。  IObserverインターフェイスおよびIObservableインターフェイスを実装する方式では、UI側でIObserverインターフェイスを実装し、Subject側でIObservableインターフェイスを実装する必要があるが、Eventモデルではメンバ『イベント』デリゲートの設計に集中すれば(まぁまぁ)良い。  オブジェクトbutton1(event sender)においてオブジェクトがクリックされたという「イベント」が発生すると、オブジェクトbutton1(event sender)は、それがクリックされたという「イベント」を、メンバ『イベント』オブジェクト"button1.Click"(event receiver)に送信する。 (←この部分こそ、まさに、”イベントデリゲート呼び出しはクラス内部からのみ可能”の規則が絡んでくるところ) 「クリック・イベント」を受け取ったメンバオブジェクトClickは、(3)で登録されている「イベントハンドラ」(処理ブロックの付いたメソッド) private void button1_Click( object sender, EventArgs e ) { ・・・ } に、イベントが発生したオブジェクトと、発生したイベントの情報が格納されたEventArgs型オブジェクトの二つのオブジェクトをアーギュメントとして渡すことが出来、イベント処理が実行される。  良いサイトを紹介してくれた#1さんと、忌憚のないご意見を頂いた#3さんに、感謝いたします。

すると、全ての回答が全文表示されます。
  • Werner
  • ベストアンサー率53% (395/735)
回答No.2

> 本来イベントハンドラと呼ぶべきメソッド名をアーギュメントとして取り得る、 > 単なるデリゲート型クラスにしか思えないのですが。 「メソッド名」は文字列ではなく、メソッドそのものと思っていいよね? (名がついてるとどうも文字列のことに思えてしまう) あと、デリゲートonKeyDownのアーギュメントとは? もしかしてこの部分のことなのかな? > this.onKeyDown = onKeyDown; デリゲートonKeyDownもイベントによって呼び出されるものではあるので イベントハンドラの意味からするとおかしくない気もするけど、 C#では「イベント変数にイベントハンドラ(デリゲート)を追加する」みたいな 言い方をするので確かにちょっと違和感はあるかも。 気になるなら、ページ最下部に「お問い合わせ」があるので そこから問い合わせてみてはどうでしょう。

mha01
質問者

お礼

再び回答いただきまして恐縮です。 >> 本来イベントハンドラと呼ぶべきメソッド名をアーギュメントとして取り得る、 >> 単なるデリゲート型クラスにしか思えないのですが。 >「メソッド名」は文字列ではなく、メソッドそのものと思っていいよね? >(名がついてるとどうも文字列のことに思えてしまう) >あと、デリゲートonKeyDownのアーギュメントとは? >もしかしてこの部分のことなのかな? >> this.onKeyDown = onKeyDown; ここでのメソッド名とは、 this.Button1.Click += new System.EventHandler( this.Button1_Click );  ←(1) において、デリゲートクラスであるEventHandlerが、具現化する際にアーギュメントとして用いているthis.Button1_Clickの内の、「Button1_Click」の部分に相当するものです。 もっとも、サイトのサンプルでは、KeyboadEventHandlerという名称のデリゲートクラス型(何でデリゲートクラス名としてEventHandlerなんていう、いかにもイベントハンドラと混同しやすい名前をわざわざ付けるのかも分からないんですが)を定義しているので、 delegate void KeyboadEventHandler(char eventCode); KeyboadEventHandlerデリゲートクラス型のオブジェクト変数として宣言されたonKeyDownのアーギュメントは、メソッドじゃなくてchar型変数のeventCodeになるのですけど、 本来、イベントハンドラとは(1)のButton1_Clickメソッド(その実装はForm1.cs内でプログラマが行います)のような、きちんとした実体のあるメソッドのことを呼んでいるわけで、そのメソッドへの参照を含む存在+αに過ぎないデリゲートオブジェクトをイベントハンドラと呼ぶべきではないと思うわけです。 >気になるなら、ページ最下部に「お問い合わせ」があるので 気がつきませんでした。親切なサイトですね。問い合わせてみます。

すると、全ての回答が全文表示されます。
  • Werner
  • ベストアンサー率53% (395/735)
回答No.1

以下のページを読めば分かると思います。 (私が説明してもこれ以上のことは言えないので参考ページの提示だけ^^;) イベント (C# によるプログラミング入門) http://ufcpp.net/study/csharp/sp_event.html

mha01
質問者

お礼

回答ありがとうございます。 お陰でeventキーワードの意義は理解できたのですが、サイト内でイベントとイベントハンドラが混同されているように思えてなりません。 KeyboardEvendHander onKeyDown; 「このようにしてイベント待受け部から独立させたイベント処理部(この例においては onKeyDown デリゲート)のことをイベントハンドラと呼びます。」 これって、正しいんでしょうか? 私には、本来イベントハンドラと呼ぶべきメソッド名をアーギュメントとして取り得る、単なるデリゲート型クラスにしか思えないのですが。 或いはむしろ、「イベントレシーバー」と呼ぶべきものではないのでしょうか?

mha01
質問者

補足

いろいろ調べてみた結果、やはり、「イベントハンドラ」は、イベントデリゲートを介して呼び出されるメソッドであることが分かりました。 http://msdn.microsoft.com/ja-jp/library/17sde2xt.aspx 更新 : 2007 年 11 月 ”イベントは、アクションの発生を知らせるために、オブジェクトによって送信されるメッセージです。アクションは、ユーザーがマウスのクリックなどの対話的操作を行った場合や、なんらかのプログラム ロジックによってトリガされた場合などに発生します。イベントを発生させるオブジェクトをイベントの送信元(event sender)と呼びます。イベントをキャプチャし、そのイベ ントに応答するオブジェクトをイベントの受信側(event receiver)と呼びます。 イベント通信では、イベント送信元のクラスは、発生させたイベントをどのオブジェクトまたはメソッドが受信する (処理する) かについての情報を持っていません。そこで、送信元と受信元との間を仲介するもの (つまりポインタ的な機構) が必要になります。.NET Framework では、関数ポインタの機能を提供する特別な型 (Delegate) が定義されています。 デリゲートは、メソッドへの参照を保持できるクラスです。他のクラスとは違って、デリゲートクラスはシグネチャを持ち、このシグネチャに一致するメソッドへの参照だけを保持できます。これにより、デリゲートはタイプセーフな関数ポインタやコールバックと同等の機能を持つことができます。デリゲートにはさまざまな用途がありますが、ここではデリゲートのイベント処理機能について説明します。デリゲート クラスは、宣言すると、定義は不要です。デリゲート宣言によってデリゲートのシグネチャが与えられ、共通言語ランタイムによって実装が提供されます。次の例は、イベント デリゲート宣言です。 規約により、.NET Framework のイベント デリゲートは、そのイベントの発生元と、そのイベントのデータという 2 つのパラメータを持ちます。 カスタム イベント デリゲートは、イベントがイベントデータを生成する場合にだけ必要です。マウスのクリックなどのユーザーインターフェイス イベントの一部を含め、多くのイベントはイベントデータを生成しません。イベントがデータを生成しない場合には、データなしイベント用のクラスライブラリに用意されているイベントデリゲートの System..::.EventHandler が適しています。その宣言を次に示します。 イベント デリゲートはマルチキャストなので、複数のイベント処理メソッドへの参照を保持できます。詳細については、「Delegate」を参照してください。デリゲートでは、イベント処理を柔軟に、そして詳細に制御できます。デリゲートは、イベントに対して登録されている 「イベントハンドラ」のリスト を管理することで、そのイベントを発生させるクラスのイベントディスパッチャとして動作します。”

すると、全ての回答が全文表示されます。

関連するQ&A