14
$\begingroup$

In C#, events and event listeners have direct support within the language, with event being a keyword, and event declarations being a special kind of member declaration in a class.

The language documentation lists three language design goals for events:

  • Enable very minimal coupling between an event source and an event sink. These two components may not be written by the same organization, and may even be updated on totally different schedules.
  • It should be very simple to subscribe to an event, and to unsubscribe from that same event.
  • Event sources should support multiple event subscribers. It should also support having no event subscribers attached.

However, all three of these goals could very well be met by implementing event listeners as a class or interface in the standard library, with Subscribe, Invoke and Unsubscribe methods (and overloaded + and - operators to support += and -= for subscribing and unsubscribing), and then user-defined classes could have fields for their event listeners, rather than events being a distinct kind of class member.

Typically, there is a preference for designers to implement features in the standard library when possible, rather than as intrinsics, to keep the compiler and the language specification simpler. Also, using a standard interface would allow alternative implementations to be provided (which might offer different guarantees with respect to order of execution, or threading) without unduly privileging one implementation as an intrinsic with special syntax. Additionally, having event as a keyword makes it more awkward to use as an identifier (as an identifier it must be spelled @event), and if event listeners are just objects then you can pass around references to them, which can be useful for some purposes.

So, why did the C# designers choose to make event listeners an intrinsic language construct?

$\endgroup$
4
  • $\begingroup$ Related $\endgroup$
    – Seggan
    Commented Aug 19, 2023 at 1:54
  • $\begingroup$ BTW there isn't that much to them, events are syntactic sugar around multicast delegates (with compiler-generated thread safe subscribe/unsubscribe) $\endgroup$
    – user1030
    Commented Aug 19, 2023 at 7:42
  • $\begingroup$ @harold That's fair, but it still means the spec has to treat "event accesses" differently to other expressions which produce a value, e.g. here and here. Is there any upside to the spec treating events so specially? $\endgroup$
    – kaya3
    Commented Aug 19, 2023 at 11:23
  • $\begingroup$ @kaya3 I don't know, and it being a shallow layer of syntactic sugar isn't really an argument either way, is it? On the one hand it's not such a big deal to offer it, on the other hand not having it in the language wouldn't be all that annoying for users either (especially considering that most event-subscription happens in WinForms initialization code generated by the Forms Designer.. and event unsubscription is almost unheard of) $\endgroup$
    – user1030
    Commented Aug 19, 2023 at 15:07

3 Answers 3

6
$\begingroup$

Within the .NET framework's type structure, events and properties are treated separately from methods and fields, even though properties could have been handled by simply having programmers declare a pair of "get" and "put" methods, and events by having programmers declare "subscribe" and "unsubscribe" methods. If an interface coded in another language inclues an event, the only way C# program would be able to implement that interface would be if C# recognizes the concept of events and generates the suitable type information for them.

Also, some other .NET languages have more substantive support for events. In VB.NET, if field declaration syntax is used but, a "WithEvents" keyword added, the compiler will auto-generate a property whose handler will automatically handle subscription and unsubscription of any method which is declared with the "Handles" keyword and the "field" and event (e.g. "Handles MyThing.Activated")(*). While C#'s event handling is sufficiently barebones that it does nothing to offer any real advantage for .NET's recognition of events, that doesn't mean all .NET languages need to be so limited.

(*) While VB.NET doesn't seem to garner much respect, and while its event handling isn't perfect, event hookup is much more convenient in the VB.NET IDE than it was in the C# IDE (at least as of the last time I used it). One can click a control and then use a pull-down menu to select an event, and it will generate an event handler stub which is declared as "Handles" and the appropriate control. Each control has a WithEvents "field", and when that field is set to refer to a control, any event for which a Handles function exist will automatically be subscribed, without the source code that assigns the field having to know or care about what particular events might exist.

$\endgroup$
6
$\begingroup$

Neglected by the existing answers so far is backwards compatibility.

Specifically, backwards compatibility with the COM and OLE technologies, and the (now so-called "classic") VB language which is designed to harness them.

The Event member type exists in .NET almost certainly because it exists in VB.

And it exists as its own thing in VB, because assembling an event and handler from the basic building blocks in COM (with all the support for "dispatching"/late binding and type discovery too!) is a murderously complicated pattern. Write your own, you say? I can hear the deep roar of the Devil laughing!

The specific way in which VB events work, was amongst the most desirable and productive features of that language. Many of the general concepts of VB are still unsurpassed, as shown by the fact that Microsoft continues massive maintenance efforts for "Winforms" (which is essentially the .NET implementation of VB's visual form designer and associated system of UI programming).

And what VB does to tame the complexity of implementing events within the COM framework, .NET had to have a facility to tame in exactly the same way, because .NET must be capable of working together with COM and VB without undue fuss (including the fact that COM and VB use "unmanaged" memory).

It may be that if .NET had been unmoored completely from Windows and from COM, then a different implementation for events would have been possible - although I wouldn't speculate idly about these matters, without understanding all the corner cases.

$\endgroup$
2
  • 1
    $\begingroup$ indeed, almost any time Microsoft seems to have done something weird, it's because of backward compatibility, often to things that seem totally unconnected to modern computing (e.g. file naming conventions that exist because of CP/M, an OS that hasn't been in common use since the early 80s). It's basically their corporate mantra. $\endgroup$
    – occipita
    Commented Oct 3, 2023 at 10:42
  • $\begingroup$ @occipita, indeed, although in this case, I'm not convinced we aren't dealing with a tried-and-tested feature whose goodness remains current, rather than a mere backwards compatibility. It would certainly be easier to roll your own event in .NET than it would have been in COM, but it's still useful not have to (in the same way that .NET distinguishes properties from method calls), and I'm still fond of the VB style designer and UI events system. $\endgroup$
    – Steve
    Commented Oct 3, 2023 at 13:17
1
$\begingroup$

I think you are ignoring the context of the language design. C# is a .NET CLR language originally intended to run Windows and easily produce windows desktop applications. Windows desktop applications make heavy use of the windows event messaging queue as does the predecessor to the CLR (visual basics runtime).

Neither VB.NET or C# followed VB6 lead of strictly using a naming convention, both in their own way extended event handling making events a first class citizens of the language.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .