C# - Event keyword advantages?

筅森魡賤 提交于 2019-11-27 19:01:53

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).

Basically, I wanted the derived classes to use these events as their own. The only way to do this was to expose the backing variable of the events as protected, so the derived classes could raise the events.

The usual way to handle this is not to expose the field, but to expose a method to raise the event.

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

This not only allows derived classes to raise the event, but also allows derived classes to do something before any subscribed handlers actually get called.

To answer your actual question, though:

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

One advantage not yet mentioned (I think):

public event PropertyChangedEventHandler PropertyChanged;

can be changed to

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

without requiring a recompile of all users of your library. You might want something like this if you later find a reason to not simply store the handlers in a private field. This is the same advantage of an auto-implemented property over a field.

I think you can easly compare 'event' keyword to accessors but you have some other benefits coming from 'event' keyword:

  • easier to read, everyone knows what 'event' means
  • less work, you don't need to create special functions to subscribe and unsubscribe from delegate variable
  • adding to or removing from delegate that has 'event' keyword has 'lock' (synchronization) added.
  • IDE / frameworks can interpret 'events' and help you
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!