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