While moving from C++/MFC to C#/Windows Forms has been a very positive experience for me, it didn't quite live up to the expectation I had that I could send objects in all directions and never have to worry about deleting them when they are no longer required. The problem is, when you add an event handler to an event, the event will hold a reference to the object that contains the event handler, and so long as that reference is there the garbage collector can't collect the object containing the event handler. Thus while the need to call
delete is gone, excessive use, on my behalf, of events has led me to a point where I need to track when objects are no longer required so that I can remove their event handlers from the event that they are servicing, and thus enable them to be garbage collected.
For a couple of years, I have been using many workarounds for this problem, including changing my coding style to reduce the incidence of this problem, and keeping lists of weak references of delegates that I iterate over to simulate events, but I finally I decided to sit down and write a simple-to-use solution to this problem that would allow me to use events in the way that I want to.
I am not the first person to try to solve this problem. Microsoftie Greg Schechter has a very inspiring article on his blog about the problem in general, and the solution that he came up with. While the solution was good, it just didn't quite fill my needs as it required changing my existing codebase too much.
Ian Griffiths of Interact Software Ltd. UK had exactly the sort of solution I was looking for on his blog but unfortunately it didn't quite work. Tricky problem this one.
Wesner Moise mentions in his blog that he talked about weak delegates with the .NET Bass Class Library team when he had dinner with them back in March 2005, but I haven't seen any mention anywhere of when such a feature would be implemented so I've decided to go ahead with my own solution. He also mentions on the same page that he has seen two experts screw up an implementation of weak delegates, so here's hoping, with all the possible scrutiny that this article might get, that I haven't added my name to the list of people who have screwed this up.
Using the Code
I have two ways of using weak event handlers depending on whether you need speed, or simplicity. The simple way to use weak event handlers is to use the
WeakEventHandlerFactory class which requires that you create one instance of the
WeakEventHandlerFactory in your class:
private WeakEventHandlerFactory eventHandlers;
And then add as many event handlers as you want, to any event source, using the
To remove an event handler, use
Not really too far removed from the code that is normally used to add and remove event handlers, is it? It should be noted that a new feature of the C# 2.0 compiler is that it will convert a function name to an event handler, so
eventSource_EventSourceChanged will be converted to
When your object is garbage collected, the
WeakEventHandlerFactory will get garbage collected around the same time, and its finalizer will remove all of the event handlers that it has created that haven't been removed yet. It doesn't matter if there is a delay between your object being garbage collected and the event handler factory being garbage collected as the event handler factory will not attempt to pass on events after your object has been garbage collected.
The caveat with using the event handler factory is that it is 40x slower than adding or removing normal event handlers. For some situations this is unacceptable, so I have created a
WeakEventHandler<> class that requires a little more code to use, but in fact ends up being 2x faster to add and remove when compared to normal event handlers. To use Weak Event Handlers directly a little more code and care is required. For each event handler in your class, you need to have an object like the following in your class declaration:
private WeakEventHandler<MyEventArgs> eventSourceChangedHandler;
Then in your constructor you initialize the
WeakEventHandler<> object in the following way:
eventSourceChangedHandler = new
This is similar to the way you initialize a normal event handler, except that you need to keep an instance of the
WeakEventHandler<> in your class. To use the
WeakEventHandler<> object, simply add it or remove it as you would a normal event handler:
eventSource.EventSourceChanged += eventSourceChangedHandler;
eventSource.EventSourceChanged -= eventSourceChangedHandler;
The difference though is that you must remove the event handler before your object has been finalized otherwise your application will bomb with a null reference exception next time the event source fires an event that is handled by a
WeakEventHandler<> in your object. Therefore your finalizer needs to remove the
WeakEventHandler<> like so:
eventSource.EventSourceChanged -= eventSourceChangedHandler;
Under the Hood
I've written four utility classes for creating Weak Event Handlers:
This class is exactly what the class name says. It is a weak reference to an event handler. This class is used by the
WeakEventHandlerInternal only, and there should not be any need to use it directly.
This class contains methods to add an event handler to the event source, and remove an event handler from the event source. All the required details such as the event source object and the event name are stored in this class so that it can remove itself from the event source should the original event handler be garbage collected.
As events can't be passed in through methods, the
AddHandler method uses reflection to add an intermediate event handler to the event source:
public void AddHandler(object eventSource, string eventName)
this.eventName = eventName;
weakReferenceToEventSource = new WeakReference(eventSource);
EventInfo eventInfo = eventSource.GetType().GetEvent(eventName);
RemoveHandler method uses reflection to remove the intermediate event handler:
public void RemoveHandler()
object eventSource = weakReferenceToEventSource.Target;
if (eventSource != null)
EventInfo eventInfo = eventSource.GetType().GetEvent(eventName);
When the event gets fired, the intermediate event handler handles it. It's at this point that a test is done to see if the original event handler has been garbage collected, and if so then the intermediate event handler removes itself from the event source.
WeakEventHandlerInternal class is used internally for storing weak event handlers. This class should not be used directly, so I made the constructor
internal. I have a class called
WeakEventHandler to be used directly that is 8x faster than
WeakEventHandlerInternal for adding and removing events. The
WeakEventHandlerInternal class is a container for the strong reference to the original event handler, and also contains an instance of the
WeakReferenceToEventHandler class. It contains methods for adding, removing, and comparing weak event handlers for equality. It is used by the
WeakEventHandlerFactory is the class that can be used to create weak event handlers. It contains two methods:
AddWeakHandler method creates a weak reference to the original event handler, but also stores a strong reference to the event handler so that it isn't garbage collected as soon as we leave the method. The weak reference and strong reference are stored together in an object that is added to an internal list.
RemoveWeakHandler does a search through all the stored event handlers looking for a match, and removes the event handler if it finds a match. This method returns a flag that indicates if it was successful or not.
This class can be used directly, but cautiously, for directly creating weak event handlers. It sacrifices ease of use for speed. An instance of
WeakEventHandler must be held for each event handler that is represented by a
WeakEventHandler object, and each
WeakEventHandler object must be removed from the source event before the event handling object is garbage collected.
Using the Sample Application
If you compile the project linked in at the top of this article, you will get an application that looks like the image at the top. This application demonstrates the usefulness of a weak event handler.
The application has three
DataGrid controls that are used for editing the contents of up to three collections. Above each
DataGrid is a unique identifier for the collection being edited in that
DataGrid, as well as the total of all the values held in that collection.
If you edit one of the collection items, the total displayed above the
DataGrid will be updated. If you remove one of the items, you will see a message in the log window indicating that the event handler was successfully removed from the item that you removed from the collection. From this you can deduce that each item in the collection has an event that fires when you change the item. Thus each item has a reference to its parent collection(s) as it is the collection that handles the event and updates the value of the total held in the collection object. The purpose of this application is to show that a weak reference to the event handler is used allowing a container of objects (the collection) to be garbage collected if it is no longer required, even if the items in the collection still exist.
Now for the fun part. Below each
DataGrid are four buttons. They allow you to display, or copy one of the other two collections.
When you copy a collection, a new collection is created and the objects from the source collection are copied into it. Hitting the "Force Garbage Collection" button will force the replaced collection to be garbage collected if it is no longer being displayed anywhere, and the log window will show a message indicating which collection was garbage collected.
Editing an item in a copied collection will update the collection it was copied from, but items added to or removed from the new collection will have no effect on the source collection.
When you "View a Set", the actual collection itself will then be displayed in the destination
DataGrid, as well as the source
DataGrid. Actions of adding/deleting/editing objects in one
DataGrid will be mirrored in the other
The sample application includes a little benchmark to show how fast different event handler types can be added and removed. I tested adding and removing 1,000,000 event handlers on an old 3.0GHz Pentium 4 and got the following results:
Speed Test: Adding and Removing 1000000 Event Handlers
Adding Normally.........Seconds: 0.5781361
Removing Normally.........Seconds: 0.3906325
Adding WeakEventHandler.........Seconds: 0.156253
Removing WeakEventHandler.........Seconds: 0.2343795
Adding WeakEventHandlerInternal.........Seconds: 2.2812938
Removing WeakEventHandlerInternal.........Seconds: 1.9687878
Adding using WeakEventHandlerFactory.........Seconds: 19.7191286
Removing using WeakEventHandlerFactory.........Seconds: 17.1253288
In the sample application I have set the number of event handlers to add and remove to 100,000 so that you don't have to wait too long to see your own results.
Sample Code Included in the Sample Application
There are two collection classes included in the source code for the sample application:
SubTotalCollection uses the
EventHandlerFactory to create weak event handlers, and
SubTotalCollectionFast uses the
WeakEventHandler class directly.
SubTotalCollectionFast is a good example of managing
WeakEventHandler objects. It adds a handler when a
SubTotal object is added to the collection, it removes a handler when a
SubTotal object is removed from the collection, and when it is finalized or cleared it removes event handlers from all the
SubTotal objects still in the collection.
The sample application just uses the
SubTotalCollection class. To make it use the
SubTotalCollectionFast class, just do a search and replace in the Form1.cs file replacing
Points of Interest
DataGrid control is a lot easier to use than the old one, for editing simple collections. In this sample application, I have objects of type
SubTotal in a collection that I want to edit in a
DataGrid. There were three steps to doing this. The first was declaring a collection class that inherited from
BindingList, like so:
public class SubTotalCollection : BindingList<SubTotal>
Then in Form.cs I created a binding source, attached it to the
DataGrid, and attached a collection to the binding source, and that was it:
BindingSource leftSource = new BindingSource();
dataGridViewLeft.DataSource = leftSource;
leftSource.Source = new SubTotalCollection();
Between this version and the first version posted on September 23rd, 2005, I had many attempts at making the factory faster. After putting in a
Dictionary for finding matching event handlers in the
RemoveHandler method I tried changing it to
SortedDictionary<,>, however for this purpose the
SortedDictionary<,> seemed to take twice as long as using the
- Original article submitted on September 23rd, 2005.
- October 13th 2005 - improved speed, added more comments, added faster
- March 7th 2007 - fixed a bug in the faster
WeakEventHandler class found by Stéphane Issartel.