Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice in declaring events in C#

I know the following two methods work, but I wonder if one is better in terms of performance / maintenance / whatever.

The short way:

  public event EventHandler MyEvent;

The long way:

  private EventHandler _myEvent;
  public event EventHandler MyEvent
  {
     add { _myEvent += value; }
     remove { _myEvent -= value; }
  }

The long way seems similar to encapsulating members with properties, which is indeed a good practice. But does this apply to event handlers?

like image 709
Johnny5 Avatar asked May 28 '13 12:05

Johnny5


People also ask

Which of the following are the best practices to be followed when using event based asynchronous pattern?

Do not define an EventArgs class for returning methods that return void . Instead, use an instance of the AsyncCompletedEventArgs class. Ensure that you always raise the MethodNameCompleted event. This event should be raised on successful completion, on an error, or on cancellation.

How is event implemented in C#?

To define an event, you use the C# event or the Visual Basic Event keyword in the signature of your event class, and specify the type of delegate for the event. Delegates are described in the next section.

What is the difference between delegates and events in C?

A delegate specifies a TYPE (such as a class , or an interface does), whereas an event is just a kind of MEMBER (such as fields, properties, etc). And, just like any other kind of member an event also has a type. Yet, in the case of an event, the type of the event must be specified by a delegate.

What do you mean by event in C?

Events enable a class or object to notify other classes or objects when something of interest occurs. The class that sends (or raises) the event is called the publisher and the classes that receive (or handle) the event are called subscribers.


3 Answers

In this case, the argument of "good practice" is a little tricker; the first is a "field-like event"; you note:

The long way seems similar to encapsulating members with properties,

but: this is encapsulated (behind add/remove) either way; so by comparison to properties, it is really the difference between:

public int Foo {get;set;}

and

private int foo;
public int Foo {
    get { return foo; }
    set { foo = value; }
}

In which case I would say "use the first one unless you have an actual reason not to" - it is still hidden behind accessors. Additionally, it is important to note that your second example is not what a field-like event (the first example) expands to : the compiler adds thread-safety into the mix. So: I would say use the first sample:

public event EventHandler MyEvent;

Note that the "how" for the thread-safety depends on which compiler version (and indeed, which specification) you use. In recent Microsoft C# compilers, it does this with Interlocked operations (CompareExchange etc), so it does not require a dedicated private synchronization object.

like image 64
Marc Gravell Avatar answered Oct 05 '22 15:10

Marc Gravell


The first way does exactly the same underneath with creating private EventHandler with the name MyEvent. When it's accessed within the class event handler is returned (i.e. no problem with calling delegate) when it's called outside of class (myClassInstance.MyEvent += SomeHandler/myClassInstance.MyEvent -= SomeHandler) Add/Remove methods are called respectively. And these methods are the same (except they add thread-safety) as those you've written in the second way.

So why do you want to write more code when you actually don't need it?

like image 39
Leri Avatar answered Oct 05 '22 15:10

Leri


To check what Marc Gravel mean i tried the following code:

public event EventHandler MyEventShortWay;

private EventHandler _myEvent;
public event EventHandler MyEventLongWay
{
    add { _myEvent += value; }
    remove { _myEvent -= value; }
}

I was surprised by what was generated (I edited the decompiled variable name) :

private EventHandler _myEventShortWay;

public event EventHandler MyEventShortWay
    {
        add
        {
            EventHandler handler2;
            EventHandler myEventShortWay = this._myEventShortWay;
            do
            {
                handler2 = myEventShortWay;
                EventHandler handler3 = (EventHandler)Delegate.Combine(handler2, value);
                myEventShortWay = Interlocked.CompareExchange<EventHandler>(ref this._myEventShortWay, handler3, handler2);
            }
            while (myEventShortWay != handler2);
        }
        remove
        {
            EventHandler handler2;
            EventHandler myEventShortWay = this._myEventShortWay;
            do
            {
                handler2 = myEventShortWay;
                EventHandler handler3 = (EventHandler)Delegate.Remove(handler2, value);
                myEventShortWay = Interlocked.CompareExchange<EventHandler>(ref this._myEventShortWay, handler3, handler2);
            }
            while (myEventShortWay != handler2);
        }
    }

    private EventHandler _myEvent;

    public event EventHandler MyEventLongWay
    {
        add
        {
            this._myEvent = (EventHandler) Delegate.Combine(this._myEvent, value);
        }
        remove
        {
            this._myEvent = (EventHandler)Delegate.Remove(this._myEvent, value);
        }

    }
like image 29
Guish Avatar answered Oct 05 '22 14:10

Guish