Why assign a handler to an event before calling it? - c#

Basically, I've seen this used all to often:
public event MyEventHandler MyEvent;
private void SomeFunction()
{
MyEventHandler handler = this.MyEvent;
if (handler != null)
{
handler(this, new MyEventArgs());
}
}
When it could just as easily be done like so:
public event MyEventHandler MyEvent;
private void SomeFunction()
{
if (MyEvent != null)
{
MyEvent(this, new MyEventArgs());
}
}
So, am I missing something? Is there some reason people assign the event to a handler, then raise the handler instead of the event itself? Is it just "best practice"?

The assignment to a local variable ensures that if the event gets unregistered between the if and the actual invocation, the invocation list will not be null (since the variable will have a copy of the original invocation list).
This can easily happen in multithreaded code, where between checking for a null and firing the event it may be unregistered by another thread.
See this SO question and answers.

Thread safety.
What happens if between the time you check if MyEvent is null and you fire MyEvent, another thread comes along and unsubscribes from the event?

Related

Why to define a reference to the event before call the event invoke?

I found some example of simple event sending.
I don't understand the line EventHandler<string> handler = MyEvent;
Why they need to define a reference to the event and not just use the myEvent to make the invoke?
The code
public event EventHandler<string> MyEvent;
protected void SendEvent(string e)
{
EventHandler<string> handler = MyEvent;
if (handler != null)
{
handler(this, e);
}
}
I found the answer here.
In multithreaded environment it is possible for client do unsubscribe from event after check for null, but before the actual invocation and MyEvent in that case will be null.
The reason is to due to thread safety. Between the null check and invocation, an event handler can be unsubscribed from on another thread, leaving you with a null value if you don't make that assignment.
if (MyEvent!= null)
{
// If MyEvent is set to NULL (unsubscribed) in another thread
// between these two lines, the program crashes.
MyEvent(this, e);
}
EventHandler<string> handler = MyEvent;
if (handler != null)
{
// GC cannot connect MyEvent because there is additional reference to it - handler.
// handler is local and cannot be set to NULL from another thread.
// The code is thread safe.
handler(this, e);
}

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

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();
}
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.
static void CallIfNotNull(this Action action)
{
if (action != null) action();
}
As an extension method, this is quite convenient to use.
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.
public static void Call(this Action action)
{
var safeAction = Interlocked.CompareExchange(ref action, null, null);
if (safeAction != null)
safeAction();
}
Using the null conditional operator keeps the test but is less verbose so works for me. I don't imagine it resolves the race condition that others have mentioned.
ResetTradesEvent?.Invoke();
This is suggested automatically in Visual Studio 2017.

.net Event Confusion

I have a data structure class that is a child of a larger data/state class.
The inner data structure fires an event when the contained data changes. This event is consumed by the larger data/state class. The data/state class then fires its own event so that it may pass additional information along to the next event handler.
Public class Data
{
//properties and objects go here
public int Count
{
get { return _count; }
internal set
{
//if the count grew simply set _count
if (value != _oldCount)
{
_oldCount = _count;
_count = value;
}
//if the count shrank then set the count and trigger an event if the count is under 100
else
{
_oldCount = _count;
_count = value;
if (_count < 100)
{
CountChanged(this, new EventArgs());
}
}
}
}
public event EventHandler CountChanged;
}
The above event is consumed by this event handler
Data.CountChanged += new EventHandler(DataCountChanged);
private void DataCountChanged(object sender, EventArgs e)
{
DataRemoved(this, e); //Handle the old event and trigger a new event to pass along more information
}
public event EventHandler DataRemoved;
Finally the second event should be handled by another event handler to do some work. Unfortunately the call to trigger the second event fails with a NullReferenceException more often than not. Why?
----EDIT----
I understand that checking for Null will prevent the exception. The confusion is why this event is Null in the first place =D
You should always raise events using the following pattern to avoid null references and threading issues:
private void DataCountChanged(object sender, EventArgs e)
{
var dr = DataRemoved;
if (dr != null)
{
dr(this, e);
}
}
The reason the handler is null is that it should be viewed as a special collection of delegates. When the collection is empty the delegate has a null value. When you attach one or more handlers the collection is no longer empty and thus is no longer null.
if(DataRemoved != null && DataRemoved.GetInvocationList().Length > 0)
{
}
Assigning an empty delegate to your events may not be such a good design practice. Events are essentially delegates which are like function pointers. In other words, they are just like other reference members in your class. Unless you assign them a value or subscribe to them, they will be and should be null.
The null reference exception you get is for the same reason as declaring private MyClass; and then trying to use it before it has been assigned a value.
When you subscribe to an event, you are essentially telling the event which function to call. If your event does not have at least one such function pointer, it would not be in existence (NULL).
There is a trick to avoid the null check:
Just initialize your event as follows:
public event YourDelegate MyEvent = delegate { };
This way you do not need to check for nulls just call the event as usual:
this.MyEvent("Hi there!");
Edited
To clarify:
Declaring an event like this:
public event Action MyEvent;
It's translated automatically to:
private Action myEvent;
public event Action MyEvent
{
add
{
this.myEvent += value;
}
remove
{
this.myEvent -= value;
}
}
Therefore initializing an event like this:
public event Action MyEvent = delegate { };
It's safe because external code can not assign a null to the event itself.
You can however, assign null to the event inside the class it was declares but what really is happening is that, you are assigning null to the private delegate used by the event.
Source: Jon Skeet, C# In Depth, Events

C#: Thread-safe events

Is the implementation below thread-safe? If not what am I missing? Should I have the volatile keywords somewhere? Or a lock somewhere in the OnProcessingCompleted method? If so, where?
public abstract class ProcessBase : IProcess
{
private readonly object completedEventLock = new object();
private event EventHandler<ProcessCompletedEventArgs> ProcessCompleted;
event EventHandler<ProcessCompletedEventArgs> IProcess.ProcessCompleted
{
add
{
lock (completedEventLock)
ProcessCompleted += value;
}
remove
{
lock (completedEventLock)
ProcessCompleted -= value;
}
}
protected void OnProcessingCompleted(ProcessCompletedEventArgs e)
{
EventHandler<ProcessCompletedEventArgs> handler = ProcessCompleted;
if (handler != null)
handler(this, e);
}
}
Note: The reason why I have private event and explicit interface stuff, is because it is an abstract base class. And the classes that inherit from it shouldn't do anything with that event directly. Added the class wrapper so that it is more clear =)
You need to lock when you fetch the handler too, otherwise you may not have the latest value:
protected void OnProcessingCompleted(ProcessCompletedEventArgs e)
{
EventHandler<ProcessCompletedEventArgs> handler;
lock (completedEventLock)
{
handler = ProcessCompleted;
}
if (handler != null)
handler(this, e);
}
Note that this doesn't prevent a race condition where we've decided we're going to execute a set of handlers and then one handler unsubscribed. It will still be called, because we've fetched the multicast delegate containing it into the handler variable.
There's not a lot you can do about this, other than making the handler itself aware that it shouldn't be called any more.
It's arguably better to just not try to make the events thread-safe - specify that the subscription should only change in the thread which will raise the event.
There is no need for the private ProcessCompleted member to be an event - it could just be a field: private EventHandler<ProcessCompletedEventArgs> ProcessCompleted; - inside the class it always goes straight to the field, so the event stuff is lost anyway.
The approach you've shown with an explicit lock object isn't much more thread-safe than just having a field-like event (i.e. public event EventHandler<ProcessCompletedEventArgs> ProcessCompleted; - the only difference is that you aren't locking "this" (which is a good thing - you should ideally avoid locking on this).. The "handler variable" approach is the right one, but there are still side-effects you should be aware of.

Why must someone be subscribed for an event to occur?

Some text before the code so that the question summary isn't mangled.
class Tree
{
public event EventHandler MadeSound;
public void Fall() { MadeSound(this, new EventArgs()); }
static void Main(string[] args)
{
Tree oaky = new Tree();
oaky.Fall();
}
}
I haven't used events much in C#, but the fact that this would cause a NullRefEx seems weird. The EventHandler reference is considered null because it currently has no subsribers - but that doesn't mean that the event hasn't occurred, does it?
EventHandlers are differentiated from standard delegates by the event keyword. Why didn't the language designers set them up to fire silently in to the void when they have no subscribers? (I gather you can do this manually by explicitly adding an empty delegate).
Well, the canonical form is:
void OnMadeSound()
{
if (MadeSound != null)
{
MadeSound(this, new EventArgs());
}
}
public void Fall() { OnMadeSound(); }
which is very slightly faster that calling an empty delegate, so speed won out over programming convenience.
Another good way I've seen to get around this, without having to remember to check for null:
class Tree
{
public event EventHandler MadeSound = delegate {};
public void Fall() { MadeSound(this, new EventArgs()); }
static void Main(string[] args)
{
Tree oaky = new Tree();
oaky.Fall();
}
}
Note the anonymous delegate - probably a slight performance hit, so you have to figure out which method (check for null, or empty delegate) works best in your situation.
The recommended pattern is (.net 2.0+)
public class MyClass
{
public event EventHandler<EventArgs> MyEvent; // the event
// protected to allow subclasses to override what happens when event raised.
protected virtual void OnMyEvent(object sender, EventArgs e)
{
// prevent race condition by copying reference locally
EventHandler<EventArgs> localHandler = MyEvent;
if (localHandler != null)
{
localHandler(sender, e);
}
}
public void SomethingThatGeneratesEvent()
{
OnMyEvent(this, EventArgs.Empty);
}
}
I see a lot of recommendations for an empty delegate{} in an initializer, but I totally disagree with it. If you follow the above pattern you only check the event != null in one place. The empty delegate{} initializer is a waste because it's an extra call per event, it wastes memory, and it still can fail if MyEvent was set to null elsewhere in my class.
* If your class is sealed, you wouldn't make OnMyEvent() virtual.
You need to understand what your event declaration is actually doing. It's declaring both an event and a variable, When you refer to it within the class, you're just referring to the variable, which will be null when there are no subscribers.
Very Zen, eh?
You have to test for null when you want to raise an event:
protected void OnMyEvent()
{
if (this.MyEvent != null) this.MyEvent(this, EventArgs.Empty);
}
It would be nice if you didn't have to bother with this, but them's the breaks.
James provided a good technical reasoning, I would also like to add that I have seen people use this an advantage, if no subscribers are listening to an event, they will take action to log it in the code or something similar. A simpl example, but fitting in this context.
What is the point of raising an event if no one is listening? Technically, its just how C# chose to implement it.
In C#, an event is a delegate with some special feathers. A delegate in this case can be viewed as a linked list of function pointers (to handler methods of subscribers). When you 'fire the event' each function pointer is invoked in turn. Initially the delegate is a null object like anything else. When you do a += for the first subscribe action, Delegate.Combine is called which instantiates the list. (Calling null.Invoke() throws the null exception - when the event is fired.)
If you still feel that "it must not be", use a helper class EventsHelper as mentioned here with old and improved 'defensive event publishing' http://weblogs.asp.net/rosherove/articles/DefensiveEventPublishing.aspx
Using an extension method would be helpful in this scenario.
public static class EventExtension
{
public static void RaiseEvent<T>(this EventHandler<T> handler, object obj, T args) where T : EventArgs
{
if (handler != null)
{
handler(obj, args);
}
}
}
It can then be used like below.
public event EventHandler<YourEventArgs> YourEvent;
...
YourEvent.RaiseEvent(this, new YourEventArgs());
Thank you for the responses. I do understand why the NullReferenceException happens and how to get around it.
Gishu said
What is the point of raising an event if no one is listening?
Well, maybe it's a terminology thing. The appeal of an "event" system seems to me that all the responsibility of the fallout of the event that took place should be on the watchers and not the performer.
Perhaps a better thing to ask is: If a delegate field is declared with the event keyword in front of it, why doesn't the compiler translate all instances of:
MadeSound(this, EventArgs.Empty)
to
if (MadeSound != null) { MadeSound(this, EventArgs.Empty); }
behind the scenes in the same manner that other syntax shortcuts are? The number of boilerplate OnSomeEvent null checking methods that people have to write manually must be colossal.

Categories

Resources