Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Self-Testing delegates: avoid checking for null before invocation?

Tags:

c#

.net

Is there any smart way to avoid the verbosity of testing the nullity on an event before calling it in a generic way ? It looks obvious that if I call a delegate, I want it to be assigned.
(If I Really want/need to test its nullity I could eventually do it explicitly, but putting this test systematically is kind of tedious and verbose.)

public delegate void ResetTradesDelegate();
public ResetTradesDelegate ResetTradesEvents;

public void OnSessionRxAdmMessage(IVfxFixAppSession session, FixMessage msg)
{    
    if (ResetTradesEvent != null)  //<-- Is there "any" a way not to write this test explicitly for each delegate ?
       ResetTradesEvent();
}
like image 320
Mehdi LAMRANI Avatar asked Jul 12 '12 20:07

Mehdi LAMRANI


3 Answers

public event EventHandler NoDataEventHandler = delegate{};

Declaring an event in this way means it will never be null. It will always, at a minimum, have a single no-op event handler hooked up.

In your case, probably

public event ResetTradesDelegate ResetTradesEvents = delegate{};

Firing an event is always going to have a race condition associated with it. You're either going to risk trying to call a delegate when it's null, or calling a delegate after the event has been unhooked. Eric Lippert wrote a pretty comprehensive post on this topic here. The technique above still suffers from the second type of race condition, so the event handlers need to be robust to being called after the event has been unhooked.

like image 79
Pete Baughman Avatar answered Nov 15 '22 02:11

Pete Baughman


static void CallIfNotNull(this Action action)
{
 if (action != null) action();
}

As an extension method, this is quite convenient to use.

like image 21
usr Avatar answered Nov 15 '22 02:11

usr


You can create your event-handler with an always-subscribed no-op event:

public class MyClass
{
    public MyClass()
    {
        this.Event += (sender, e) => ();
    }

    public event EventHandler Event;

    protected virtual void OnEvent()
    {
        this.Event(this, EventArgs.Empty);
    }
}

However, this requires subscribing your event and will incur a performance penalty as the no-op delegate will still exist in the list of subscribed event handlers.


My preference here is to create a pair of extension methods to invoke any event handler, whilst performing a null-safe check:

public static void Raise(this EventHandler @event, object sender)
{
    if(@event != null)
    {
        @event.Invoke(sender, EventArgs.Empty);
    }
}

public static void Raise<TEventArgs>(
    this EventHandler<TEventArgs> @event,
    object sender,
    TEventArgs args)
    where TEventArgs : EventArgs
{
    if(@event != null)
    {
        @event.Invoke(sender, args);
    }
}

This can then be easily invoked anywhere in your library to safely raise the event:

this.ResetTradesEvent.Raise(this);

It's purely syntactic sugar; you're still doing the check on the delegate. It is however, a nice re-usable way to wrap up this smelly part of the C# language.

like image 2
Paul Turner Avatar answered Nov 15 '22 02:11

Paul Turner