Geeks With Blogs
A Technical Debtor Toward continuous improvement

This is a case of things being more complicated that I thought they should be. Since it took a while to figure this one out, I thought it was worth explaining and putting all of the pieces to the answer in one spot.

Let me set the stage. Architecturally, I have the notion of generic producers and consumers. These put items onto, and remove items from, a queue. This provides a generic, thread-safe mechanism to load balance the creation and processing of work items in our application.

Part of the IProducer(Of T) interface is:

   1: Public Interface IProducer(Of T)
   2:     Event ItemProduced(ByVal sender As IProducer(Of T), ByVal item As T)
   3:     Event ProductionComplete(ByVal sender As IProducer(Of T))
   4: End Interface

Nothing sinister there, is there?

In order to simplify our developers’ lives, I wrapped the queue with some functionality to manage the produces and consumers. Since the developer can specify the number of producers and consumers that are spun up, the queue code manages adding event handlers as the producers and consumers are instantiated.

Now, we’ve been having some memory leaks and, in order to eliminate the possibility that this was caused by weak references to event handles, I wanted to remove them. This is where it got dicey. My first attempt looked like this:

   1: For Each producer As P In Producers
   2:     RemoveHandler producer.ItemProduced, AddressOf ItemProducedHandler
   3:     RemoveHandler producer.ProductionComplete, AddressOf ProductionCompleteHandler
   4:     producer.Dispose()
   5: Next

What you can’t see in my posted code are the warnings this caused.

The 'AddressOf' expression has no effect in this context because the method argument to 'AddressOf' requires a relaxed conversion to the delegate type of the event. Assign the 'AddressOf' expression to a variable, and use the variable to add or remove the method as the handler. 

Now, what on earth does that mean? Well, a quick Bing search uncovered a whole bunch of talk about delegates. The first solution I found just changed all parameters in the event handler to Object. Sorry, but no. I used generics precisely because I wanted type safety, not because I wanted to use Object.

More searching. Eventually, I found this forum post, where Jeff Shan revealed a missing piece of the puzzle. The other revelation came from Lian_ZA in this post. However, these two only hinted at the solution. Trying some of what they suggested led to finally getting an invalid cast exception that revealed the existence of ItemProducedEventHandler.

Hold on a minute! I didn’t create that delegate. There’s nothing even close to that name in my code… except the ItemProduced event in the interface. Could it be? Naaaaah. Hmmm….

Well, as it turns out, there is a delegate created by the compiler for each event. By explicitly creating a delegate that refers to the method in question, implicitly cast to the generated delegate type, I was able to remove the handlers:

   1: For Each producer As P In Producers
   2:     Dim _itemProducedHandler As IProducer(Of T).ItemProducedEventHandler = AddressOf ItemProducedHandler
   3:     RemoveHandler producer.ItemProduced, _itemProducedHandler
   4:  
   5:     Dim _productionCompleteHandler As IProducer(Of T).ProductionCompleteEventHandler = AddressOf ProductionCompleteHandler
   6:     RemoveHandler producer.ProductionComplete, _productionCompleteHandler
   7:     producer.Dispose()
   8: Next

That’s “all” it took to finally be able to remove the event handlers and maintain type-safe code. Hopefully, this will save you the same challenges I had in trying to figure out how to fix this issue!

Posted on Tuesday, May 4, 2010 11:37 AM Tips and Tricks , Software Development , VB , DevCenter | Back to top


Comments on this post: RemoveHandler Issues with Custom Events

# re: RemoveHandler Issues with Custom Events
Requesting Gravatar...
Don't forget that you can use the true custom event syntax if you don't want Visual Basic to auto generate the event and delegate objects.

Custom Event Test As EventHandler
AddHandler(ByVal value As EventHandler)

End AddHandler

RemoveHandler(ByVal value As EventHandler)

End RemoveHandler

RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)

End RaiseEvent
End Event
Left by Bradley on May 09, 2010 10:31 AM

# re: RemoveHandler Issues with Custom Events
Requesting Gravatar...
As suggested above i also visited the forums of Jeff Shan and Lian_ZA. I followed the same way and also realised that there was a delegate created by the compiler for each event and I also managed to remove the remove the handlers. Thank you for your suggestions
Left by Kale Kapı on Feb 20, 2011 7:29 AM

Your comment:
 (will show your gravatar)


Copyright © Jeff Certain | Powered by: GeeksWithBlogs.net