Static Events

Published 1/7/2013 by Christian in Code

Using Static Events should be done with care, if you are subscribing to such an event from instances, as a race condition could occur, when subscribing and null-checking the event.
The trick here is to subscribe a trivial handler to the static event, when declaring it, eg.:

//Added a trivial handler to avoid race condition;
public static event EventHandler DataChangedEvent = delegate { };

Then you can use it without the null check.

//No need to null check. A trivial event handler has been subscribed to event.
DataChangedEvent(ToolTip, EventArgs.Empty);

Oh by the way - this trick naturally also applies to instance events.

As always, feel free to comment, or ask.

 

Edit

In C# 6.0 this can actually be done much more nicely, using the 'Null-conditional operators'.

 

DataChangedEvent?.Invoke(ToolTip, EventArgs.Empty);

 

This way you don't need to subscribe the trivial handler to the static event. So declaring it will just look like this - even for a static event:

public static event EventHandler DataChangedEvent;

You can watch Mads Torgersen brief video on C# 6.0 here:

http://channel9.msdn.com/Events/Visual-Studio/Connect-event-2014/116


Did you know that
Event -= new EventHandler(yourEventHandler)
wouldn’t unsubscribe the event handler from the event. This means that the object that contains the event still holds a reference to the object containing the event handler and visa versa. And if you try to dispose one of the object, the GarbageCollector wouldn’t collect it. It will remain in memory until both object are disposed.

The way to resolve this is to make an instance of the delegate you want to subscribe to the event, and unsubscribe this instance from the event.

An example might be in order here:

public class Foo : IDisposable
{
    public event System.EventHandler AnEvent;

    private void RaiseEvent()
    {
        if (AnEvent != null)
        {
            AnEvent(this, new System.EventArgs());
        }
    }

    void IDisposable.Dispose()
    {
        AnEvent = null;
    }
}

public class Bar : IDisposable
{
    private System.EventHandler _eventHandler = null;
    public System.EventHandler EventHandler
    {
        get
        {
            //If no instance of _eventHandler exist, create a new one
            if (_eventHandler == null)
            {
                _eventHandler = new System.EventHandler(theEventHandler);
            }
            return _eventHandler;
        }
    }

    private Foo _foo;

    public Bar()
    {
        _foo = new Foo();
        _foo.AnEvent += EventHandler; //Subscribe to AnEvent
    }

    private void theEventHandler(object sender, System.EventArgs e)
    {
        //Do the handling stuff
    }

    void IDisposable.Dispose()
    {
        _foo.AnEvent -= EventHandler; //UnSubscribe from AnEvent
        _foo = null;
    }
}


Notice that I have created an instance of the event handler delegate in the

public EventHandler EventHandler


property.
This instance (_eventHandler) is the instance that I subscribe to the event

_foo.AnEvent += EventHandler;


and unsubscribe again in Dispose

 

_foo.AnEvent -= EventHandler;

 


As always, feel free to comment or ask.