トップ回答者
interfaceの構文

質問
-
お世話になっております。
下記のように、インターフェイス構文の中に、フィールド(状態)を持つことを許されていません。inteface ICar
{
int a;// コンパルエラー}
しかし、イベントは持つことはできます。でもデリゲートは配置できません。
delegate void DelegateSome();
interface IXar
{
public event EventHandler Closed;//コンパイルOK
public DelegateSome some;//コンパイルエラー
}
eventキーワードがついたデリゲートははフィールドとみなされないということなのでしょうか。
この違いを教えていただきたいのですが。。。
よろしくお願いします。
回答
すべての返信
-
ざっくりとは、
interface に定義できるのはメタデータとメソッドだけなのです。プロパティとイベントはメタデータによって名前を付けられた特別なメソッドの塊として表現されています。
// プロパティ public int X { get; set; } public int Y { get; } // interface は使えませんが例として public int Z { get; private set; } ↓ public int get_X(); public void set_X(); public int get_Y(); public int get_Z(); private void set_Z(); // イベント public event EventHandler X; public event EventHandler Y { add; remove; }; ↓ public void add_X(EventHandler handler); public void remove_X(EventHandler handler); public void add_Y(EventHandler handler); public void remove_Y(EventHandler handler);
と、内部では「こういうプロパティやイベントがあるよ」という「メタデータ」と、そのプロパティやイベントの操作を実現するためのメソッドで構成されています。C# や VB では、これらのメタデータやメソッドを理解して自動的に読み替えてくれるようになっています。イベントの定義では add と remove の処理は必須(addできないイベントや、removeできないイベントは存在しない)なので、古くから記述が省略できるようになっています。プロパティの定義では get と set は必須ではない(get専用やset専用のプロパティが存在できる)ので省略できないようになっています。
# 一部のプログラム言語ではプロパティやイベントを解釈できなくて、こういったプロパティやメソッドを実現しているメソッドを直接呼び出さなければならない場合もあります。
-
すこし補足をしておきます。実体のあるクラスでイベントを宣言すると、
public event EventHandler X; ↓ // EventHandler を保存するフィールド private EventHandler _X; // イベントのメタデータ public event EventHandler X { add { this.add_X(value); } remove { this.remove_Y(value); } } // 追加ハンドラ private void add_X(EventHandler value) { this._X = this._X + value; } // 削除ハンドラ private void add_Y(EVentHandler value) { this._X = this._X - value; }
こんなイメージで、フィールドとメソッドと、そのメソッドの実装が自動的に作成されます。 -
イベントは抽象定義(インターフェイスのように、本体を持たない、宣言だけのもの)と自動実装(裏にデリゲート型のフィールドを自動的に作る)の見た目が同じというだけで、本当はプロパティのようなものです。
ちなみに、自動実装の結果は以下のようなものです。
// 自動実装イベント public event Action<T> X; // ↑を手動で書くなら // イベントと同名のフィールド // C# の文法上は認められていないものの、IL 的には OK。 // コンパイラーの自動実装結果はこうなっている。 private Action<T> X; // 簡易版。本当はこれに、スレッド安全性の保証用コードが入る。 public event Action<T> X { add { X = Delegate.Combine(X, value); } remove { X = Delegate.Remove(X, value); } }
IWANAGA Nobuyuki -
eventキーワードがついたデリゲートははフィールドとみなされないということなのでしょうか。
eventキーワードがついたデリゲートではありません。あくまでeventが主役であり、このイベントはこのデリゲート型を受け取るという宣言です。つまり、
public event EventHandler Closed;//コンパイルOK
は、
Closedイベントを定義しており、そのイベントはEventHandler型のデリゲートを扱いますという宣言をしています。誤解を恐れずに例え話をすれば、
Closedというメソッドが引数としてEventHandler型の引数を受け取るということに似ています。
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/ -
ご返事ありがとうございます。
>>// EventHandler を保存するフィールド
>>private >> EventHandler _X;eventをMSILにコンパイルされたときにイメージを説明して頂いていると思うのですが、
上記なんですが、デリゲートのフィールドが作成されているように見えるのですが、これは許されるのでしょうか・・・
みなさんの回答からまとめると、C#からMSILにコンパイルする際には、C#的にはフィールを持ってはいけないけど、
コンパイラはフィールドを生成しても、コンパイラだから怒られないといったところでしょうか。「MSIL言語で作成するインターフェイスは、フィールドをもってよい」ということであってますでしょうか。