Question

What are the differences, side effects, and/or preferences of these 2 different ways of adding an event handler for the SQLConnection.StateChange event? Since AddressOf creates a delegate (http://msdn.microsoft.com/en-us/library/y72ewk2b.aspx), and StateChangeEventHandler is a delegate as well, example 2 seems to just be creating nested delegates, but I'm guessing that there is some nuance that I'm missing.

From my testing they appear to work the same using either example 1 or 2. Neither throw an exception when attempting to call AddHandler more than once (my first assumption was that calling example #1 would throw an error if attempting to call AddHandler a second time since it would be adding the same reference, as where example 2 would not since it would be a new delegate instance; however, they both succeed without an exception).

Example 1: Using only AddressOf: http://msdn.microsoft.com/en-us/library/7taxzxka.aspx

AddHandler conn.StateChange, AddressOf OnConnectionStateChange

Example 2: Using an instance of the StateChangeEventHandler delegate as listed here: http://msdn.microsoft.com/en-us/library/a0hee08w(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-2

AddHandler conn.StateChange, New StateChangeEventHandler(AddressOf OnConnectionStateChange)

Also, is there a need to remove this handler prior to dispose/end of the using block via RemoveHandler, or will SQLConnection.Dispose take care of that for you? I'm not sure how you would remove the event handler if using the StateChangeEventHandler in example #2 below from the MSDN site, since the instance of StateChangeEventHandler delegate is not stored in a local variable, so you have no reference of the handler to remove (you would have to do something similar to Example #4).

Example #3: RemoveHandler using just AddressOf

    Using conn As SqlConnection = New SqlConnection("...")
        AddHandler conn.StateChange, AddressOf OnConnectionStateChange
        conn.Open()
        '...do work here...
        conn.Close()
        'Then do i need this?
        RemoveHandler conn.StateChange, AddressOf OnConnectionStateChange
    End Using

Example #4: RemoveHandler using the StateChangeEventHandler

    Using conn As SqlConnection = New SqlConnection("...")
        Dim myHandler As StateChangeEventHandler = New StateChangeEventHandler(AddressOf OnConnectionStateChange)
        AddHandler conn.StateChange, myHandler
        conn.Open()
        '...do work here...
        conn.Close()
        'Then do i need this?
        RemoveHandler conn.StateChange, myHandler
    End Using

NOTE: I tagged as C# as well since the MSDN documentation also lists the same scenario for the C# example:

connection.StateChange  += new StateChangeEventHandler(OnStateChange);

vs.

connection.StateChange  += OnStateChange;
Was it helpful?

Solution

I stumbled upon this article (http://msdn.microsoft.com/en-us/library/74wy9422(v=vs.90).aspx) which mentions that AddressOf is simply short-hand for New EventHandler(AddressOf fn).

AddHandler Button1.Click, New EventHandler(AddressOf Button1_Click)
' The following line of code is shorthand for the previous line. 
AddHandler Button1.Click, AddressOf Me.Button1_Click

and it also states:

You can use the shorthand way of creating delegates anywhere the compiler can determine the delegate's type by the context

So in most cases, using New SomeEventHandlerType(AddessOf x) or just AddressOf x accomplishes the same thing. In the case of SQLConnection.StateChange, the event is Declared as Public Event StateChange As StateChangeEventHandler, so the compiler knows the correct delegate type to use, and AddressOf is smart enough to use the correct delegate type automatically for you. There is no need to use New StateChangeEventHandler(AddressOf OnConnectionStateChange), but it can be used for code clarity to show that this is not the generic EventHandler delegate type, and that it uses a custom EventArgs type.

As far as unsubscribing, to be absolutely certain to avoid resource leaks, you should remove event handler references before disposing of the subscriber object. See http://msdn.microsoft.com/en-us/library/ms366768(v=vs.120).aspx which states:

In order to prevent resource leaks, you should unsubscribe from events before you dispose of a subscriber object. Until you unsubscribe from an event, the multicast delegate that underlies the event in the publishing object has a reference to the delegate that encapsulates the subscriber's event handler. As long as the publishing object holds that reference, garbage collection will not delete your subscriber object.

In actual practice, I've seen very few examples that do this (even in the MSDN "How to: Publish Events that Conform to .NET Framework Guidelines" http://msdn.microsoft.com/en-us/library/w369ty8x.aspx). GC will take care of removing event references on the publisher when it is finalized. However, if you have scenarios where the publisher can live much longer than the subscriber, you will need to make sure the remove the event references manually. In the SQLConnection example, the connection object (i.e. the publisher of the StateChange event) has a short lifetime, so the RemoveHandler is arguably not needed. See this post for more details: .NET object events and dispose / GC

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top