Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing EventArgs Empty Correctly

I'm trying to properly understand Events and EventArgs but can't quite get a handle on the whole EventArgs.Empty property.

EventArgs implements:

public static readonly EventArgs Empty;

and allows us to create an EventHandler and call it using:

public event EventHandler<EventArgs> TestHappening;

private void MyMethod()
{
    TestHappening( this, EventArgs.Empty );
}

Now I've studied a number of classes based on EventArgs and none of them seem to implement this so I'm flying a little blind even though I've read all the documentation I could find regarding EventArgs.Empty. According to the documentation, "The value of Empty is a read-only instance of EventArgs equivalent to the result of calling the EventArgs constructor".

Based on that I've created the following implementation:

public class TestEventArgs : EventArgs
{
    public static readonly TestEventArgs Empty;

    public bool UpdatedValue { get; private set; }

    TestEventArgs()
        : this( false )
    {
    }

    public TestEventArgs( bool updatedValue )
    {
        this.UpdatedValue = updatedValue;
    }
}

public event EventHandler<TestEventArgs> TestHappening;

private void MyMethod()
{
    TestHappening( this, EventArgs.Empty );
}

Is the use of TestEventArgs.Empty instancing a class or what exactly is it doing?

Also, even though all the subclasses I checked didn't make use of Empty, they still have it available, isn't it confusing having an unusable property exposed?

Lastly, based on the various documents I studied, there were two main variances of when to actually instantiate the EventArgs. Which is considered "more" correct?:

OnTestHappening( new TestEventArgs( false ) );

private void OnTestHappening( TestEventArgs e )
{
    var handler = TestHappening;

    if ( handler != null )
        handler( this, e );
}

vs

OnTestHappening( true );

private void OnTestHappening( bool foo )
{
    var handler = TestHappening;

    if ( handler != null )
        handler( this, new TestEventArgs( foo ) );
}
like image 949
Storm Avatar asked Mar 17 '26 20:03

Storm


1 Answers

You should think for yourself if you really need the Empty field. If you don't instead to use it, you shouldn't create it. The EventArgs class doesn't have any variables or properties, so it doesn't make sense to create a new instance every time. In your case, since you have a default value, it does make more sense to have two 'empty' TestEventArgs, one for true and one for false (if you really want to and it makes sense in your scenario).

You are missing some other points in your implementation which I have fixed below:

public class TestEventArgs : EventArgs
{
    public static readonly TestEventArgs True = new TestEventArgs(true);

    public static readonly TestEventArgs False = new TestEventArgs(false);

    public bool UpdatedValue { get; private set; }

    public TestEventArgs(bool updatedValue)
    {
        this.UpdatedValue = updatedValue;
    }

    public event EventHandler<TestEventArgs> TestHappening;

    private void MyMethod()
    {
        EventHandler<TestEventArgs> eh = TestHappening;

        eh?.Invoke(this, TestEventArgs.True);
    }
}

What I have changed:

  1. Instantiated Empty as a new TestEventArgs, since that was the definition of EventArgs.Empty too.
  2. I have implemented the thread-safe version of the event handler (the second sample in your code). If the list of event handlers subscribed to the event changes, your first sample isn't safe. Your second is, and therefore you should that option.

Regarding your last point: it depends if you intend to have the calling delegates change the object (it is passing one instance vs multiple instances). In your case, since the instance can't be altered, it doesn't matter that much.

like image 173
Patrick Hofman Avatar answered Mar 20 '26 10:03

Patrick Hofman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!