34

私は最近、C# の「イベント」が実際にあることを理解するようになりました。正直、何でもないです。私の調査結果を要約すると: eventキーワードは、デリゲートにのみ適用される単純な修飾子です。

したがって、イベントのすべての「魔法」はデリゲートの操作です。それでおしまい。Microsoft のドキュメントをたくさん読みましたが、これほど簡潔にまとめられた文章はありません。私の発見を続けると、デリゲート、クラス、および構造体はすべて同じ「レベル」にあります。それらは「オブジェクト」を定義する方法です。タイプのように「オブジェクト」を意味するのではなく、カプセル化された「何か」の概念を意味します。オブジェクト指向プログラミングを言うときに「オブジェクト」という言葉がどのように使われるかのように。

とにかく、「オブジェクト」には特定の修飾子があります。たとえば、sealed、readonly、virtual、static など...このリストは、ここにあります。デリゲートの場合、eventと呼ばれる特別なものがあります。Event は、デリゲートがクラスの一部として宣言されたときに、イベントに与えられたアクセス修飾子に従ってaddメソッドとremoveメソッドのみを公開するようにします。これらのメソッドは、getおよびsetと同様の性質で定義されています。プロパティの。デリゲートの他の操作 (代入、読み取りアクセス、メソッド呼び出しなど) は、イベント デリゲートが宣言されたクラス内でのみ許可されます。私が興味深いと思うもう 1 つの点は、すべてのデリゲートにメソッド Invoke、BeginInvoke、および EndInvoke があるにもかかわらず、Visual Studio 内でそれらを表示するために移動することも、それらを説明するドキュメントを見つけることもできないことです...

わかった。以上のことをすべて理解した後、デリゲートへのアクセス方法を変更する以外に、イベント キーワードを使用する利点は何ですか? 多くの場合、イベント キーワードなしでデリゲートを宣言する方がよいようです。私が最近遭遇した状況は、2 つのイベントを含む抽象基本クラスを作成したいというものでした。この基本クラスから派生したクラスは、派生クラスに公開されているクラスの他のオブジェクトと同様に、イベントを独自のものとして使用できる必要があります (別名、派生クラスが別のクラスにない限り、プライベートではありません)。アセンブリであり、オブジェクトは internal として宣言されています)。

基本的に、派生クラスでこれらのイベントを独自のものとして使用したかったのです。これを行う唯一の方法は、派生クラスがイベントを発生できるように、イベントのバッキング変数を保護されたものとして公開することでした。コードを見ると、基本的にデリゲートを 2 回定義していたので、これはかなりばかげているように見えました。1 つは保護されたフィールドとして、もう 1 つはパブリック イベントとして。私は思った、

コンストラクターで Action の out パラメーターを持つ Event というクラスを作成した方がよいのではないでしょうか? 返されるアクションは、多くの人がデリゲートの拡張メソッドとして作成した Raise と同等であり、デリゲートが null かどうかを確認してから、デリゲートを呼び出します。Event の唯一のパブリック メソッドは、デリゲートを追加し、基になるデリゲートからそれらを削除するための Add と Remove です (+=、-=)。クラスは、これらのイベントを次のようなプロパティとして持つことができます。

public Event SomethingHappened { get; private set; }

そのクラスだけがイベントを再割り当てできるようにします。または、パブリックの読み取り専用フィールドも同様に効果的です。コンストラクターから返される out パラメーターは、クラスによって格納され、クラスがイベントを発生させたいときに呼び出されます。私はそれがばかげた回避策であることを知っていますが、それは仕事を終わらせ、イベントを引数として渡すだけでなく、基本クラスが保護されていると定義している場合、派生クラスが Raise メソッドを呼び出すことを許可します。

TLDR:

デリゲートへのアクセス方法を変更する以外に、イベント キーワードを使用する利点は何ですか?

4

3 に答える 3

25

What is the advantage of using the event keyword other than for modifying how the delegate can be accessed?

That is the primary advantage of using the event keyword. You use an event over just a raw delegate to prevent the delegate from being invoked or cleared from outside the scope of the class it is defined in, because in the case of events it is the responsibility of that class to invoke the event. External entities shouldn't be invoking it directly (they can and should be invoking the event indirectly), nor should they "care" about whether there are any other event handlers or be involved in touching them (by, for example, assigning an entirely new delegate to the field).

The specific case of wanting to allow sub-classes to fire the event is most commonly solved by having the class that defines the event creating a protected method that does nothing but fire the event. Such methods will, by convention, have the same name as the event but with "On" prefixing it.

Yes, you could create your own type that logically represents an event, is a wrapper for a delegate, and limits the functions that can be performed on that event to those that "should" be able to perform them (possibly using slightly different rules than the C# event keyword uses. This is something that is frequently used in other languages that don't have an event keyword (or possibly even delegates). The C# designers simply realized that this was a very common pattern, and felt that it was worth the energy to add the keyword to the language to help minimize the boilerplate code required to create a logical "event".

Another benefit of using the event keyword, as opposed to just having some type of delegate as a property, is that you make your intentions much clearer. If I see just a delegate property the implication is generally that it represents one method. Yes, all delegates in C# are multicast delegates, so that's not true, but it's unusual for people to leverage that functionality outside of events. People think that an Action represents one action, not a list of actions. Events also have special treatment with respect to the C# documentation. They are all listed separately, they have different icons in visual studio, etc. This all helps make the intentions and semantics of the member much clearer to someone using the class at a glance.

Finally, the event keyword ensures that there is synchronization between multiple threads, which isn't performed by the Delegate class. If multiple threads go to add handlers to an event at the same time, the event keyword ensures both are added. If you just publicly expose a delegate it's possible for one to overwrite the other due to a race condition and have one handler end up dropped on the floor. If you roll your own Event class you could provide this functionality, but it is both more boilerplate code and something that's pretty darn easy to mess up (either resulting in leaving race conditions in, or excessive synchronization resulting in lost performance).

于 2013-08-22T16:45:11.027 に答える
3

基本的に、派生クラスでこれらのイベントを独自のものとして使用したかったのです。これを行う唯一の方法は、派生クラスがイベントを発生できるように、イベントのバッキング変数を保護されたものとして公開することでした。

これを処理する通常の方法は、フィールドを公開するのではなく、イベントを発生させるメソッドを公開することです。

public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) {
  var handler = PropertyChanged;
  if (handler != null)
    handler(this, e);
}

これにより、派生クラスがイベントを発生させるだけでなく、サブスクライブされたハンドラーが実際に呼び出される前に、派生クラスが何かを実行できるようになります。

ただし、実際の質問に答えるには:

デリゲートへのアクセス方法を変更する以外に、イベント キーワードを使用する利点は何ですか?

まだ言及されていない1つの利点(私は思う):

public event PropertyChangedEventHandler PropertyChanged;

に変更できます

public event PropertyChangedEventHandler PropertyChanged
{
  add { /* custom code here */ }
  remove { /* custom code here */ }
}

ライブラリのすべてのユーザーを再コンパイルする必要はありません。後でハンドラーを単純にプライベート フィールドに格納しない理由を見つけた場合、このようなものが必要になる場合があります。これは、フィールドに対する自動実装プロパティの利点と同じです。

于 2013-08-22T16:55:50.727 に答える
0

「イベント」キーワードとアクセサーを簡単に比較できると思いますが、「イベント」キーワードには他にもいくつかの利点があります。

  • 読みやすく、誰もが「イベント」の意味を知っています
  • デリゲート変数をサブスクライブおよびサブスクライブ解除するための特別な関数を作成する必要はありません。
  • 'event' キーワードを持つデリゲートへの追加またはデリゲートからの削除には、'lock' (同期) が追加されています。
  • IDE / フレームワークは「イベント」を解釈し、あなたを助けることができます
于 2014-05-09T15:48:08.170 に答える