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?
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.
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.
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.
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.
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.
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?
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With