Jelle Druyts .NET Consultant
Just another ignorant weirdo from Antwerp, Belgium trying to make sense out of it all
Take the following event declaration (defining the parameter list immediately) in VB.NET:Public Event SomethingHappened(ByVal sender As Object, ByVal e As SomethingHappenedEventArgs)The VB.NET compiler is 'kind enough' to generate an appropriate delegate type for us behind the scenes - in this case:Public Delegate Sub SomethingHappenedEventHandler(ByVal sender As Object, ByVal e As SomethingHappenedEventArgs)Note that you can also define the delegate type yourself and declare the event more in a C# type of way:Public Delegate Sub SomethingHappenedEventHandler(ByVal sender As Object, ByVal e As SomethingHappenedEventArgs)Public Event SomethingHappened As SomethingHappenedEventHandlerThis approach is better because otherwise, a new delegate type will always be created by the compiler - even if you declare different events with an identical signature which could and should use the same delegate type. By defining the delegates yourself you have more control over what is created.
Public Event SomethingHappened(ByVal sender As Object, ByVal e As SomethingHappenedEventArgs)
Public Delegate Sub SomethingHappenedEventHandler(ByVal sender As Object, ByVal e As SomethingHappenedEventArgs)
Public Delegate Sub SomethingHappenedEventHandler(ByVal sender As Object, ByVal e As SomethingHappenedEventArgs)Public Event SomethingHappened As SomethingHappenedEventHandler
Ok so now I'm trying to determine if there are any subscribers to my event. In C# I could get away with a simple "if( SomethingHappened != null )" but in VB.NET SomethingHappened is just the event declaration, not an actual object, so I can't use "If Not SomethingHappened Is Nothing". The generated (or declared) delegate is also just a type, not an object, so I can't just go "If SomethingHappenedEventHandler.GetInvocationList().Length > 0". I spent some time surfing the web looking for an answer, and after a while I found out I should've looked at the documentation straight away. As it happens, the compiler also generates a private member field called SomethingHappenedEvent which holds the actual delegate instance used to maintain the event's invocation list. So the solution was to use "If SomethingHappenedEvent.GetInvocationList().Length > 0".
if( SomethingHappened != null )
SomethingHappened
If Not SomethingHappened Is Nothing
If SomethingHappenedEventHandler.GetInvocationList().Length > 0
SomethingHappenedEvent
If SomethingHappenedEvent.GetInvocationList().Length > 0
So when you declare an event as above, you actually get this:Public Delegate Sub SomethingHappenedEventHandler(ByVal sender As Object, ByVal e As SomethingHappenedEventArgs)Private SomethingHappenedEvent As SomethingHappenedEventHandlerAccording to the documentation, the compiler also generates some methods to add and remove event handlers but I didn't find them. Note that all these compiler-generated types and fields aren't visible in IntelliSense so they're not obvious to discover.
Public Delegate Sub SomethingHappenedEventHandler(ByVal sender As Object, ByVal e As SomethingHappenedEventArgs)Private SomethingHappenedEvent As SomethingHappenedEventHandler
I must say I'm a lot more comfortable in C# where there are no auto-generated features of type "let's-make-the-basics-easy-but-cause-confusion-for-people-that-actually-know-what-delegates-are". Delegates and Events are the core of event-driven programming in .NET and should be well understood when programming them. This is no playground for compilers, this is a must-know for developers. Another boo to VB.NET!
If you want to know about how events actually work, go read the Bedtime Story, really!