I've always invoked events as so
void onSomeEvent(string someArg) {
var h = this.EventName;
if (h != null) {
h(this, new MyEventArgs(someArg));
}
}
Today VS 2015 tells me this can be simplified:
MyEvent?.Invoke(this, new MyEventArgs(someArg));
A few questions on this latter method, which I've not seen before:
Presumably the ? after the event name is a check if the handler is null?
Assuming the handler is not null, .Invoke() seems straightforward enough
I've used the first example for years and realize it prevents race conditions... presumably the ?.Invoke() of the second example does so as well?
Presumably the ? after the event name is a check if the handler is null?
Yes. It's the null conditional operator, introduced in C# 6. It's useful in all kinds of ways.
I've used the first example for years and realize it prevents race conditions... presumably the ?.Invoke() of the second example does so as well? (see question #1)
Yes. Basically, they're equivalent. In particular, it does not evaluate the MyEvent expression twice. It evaluates it once, and then if the result is non-null, it calls Invoke on it.
Related
Suppose there is the following code snippet (I am using .NET 4.0):
private void CauseTrouble()
{
if (MyEvent != null)
{
DoSomeIrrelevantCalculations();
MyEvent();
}
}
When running a fairly large program containing this (simplified) method, in rare cases I encounter a NullReferenceException from MyEvent(). The debugger tells me that MyEvent is null even though I just checked that it is not null. What is going on here?
Now some people might immediately say: "Of course, if you have a multithreaded application, another thread might unregister myEvent before those irrelevant calculations are finished and - Boom! - you have a NullReferenceException!"
That is surely true, but before I venture deeper into the darkness of multithreading (since it is a very rare error, I often have to wait days for it to occur again), I need to know if there are any other possibilities for this to happen?
Specifically: Does an event being null after a successful non-null check necessarily mean that another thread has unregistered the event?
(Another option I could imagine is the external unmanaged code which is executed by the program as well and which has already caused some data access violations before. Is it possible that some operation there is causing the pointer to MyEvent to be overwritten? Or should this be impossible since the code snippet is part of the managed code? I am too inexperienced with that stuff to be able to tell.)
If you say now: Hey, why do you not log all register/unregister processes and check what is going on yourself: You are right. I am already on it. But as I said, with a bit bad luck it can take a week before I get an answer, and I want to check out other possibilities as well in the meantime.
Update
Things get stranger. The assumption was correct, the debugger shows that MyEvent is indeed null when being called. So I did what was recommended here and replaced
if (MyEvent != null)
{
DoSomeIrrelevantCalculations();
MyEvent();
}
with
var handler = MyEvent;
if (handler != null)
{
DoSomeIrrelevantCalculations();
handler();
}
But this still yields a NullReferenceException. Debugging shows that MyEvent is again null when handler() is called, but handler itself is not. How can a NullReferenceException be evoked if the object is not even null?
You have two options. If you're working in C# 6.0 or higher, you can use the null coalescing operator. Behind the scenes, it'll prevent this problem from happening. Here's how:
MyEvent?.Invoke();
The other option is useful if you're not using C# 6.0. Just store it in a variable first, check the variable, and then invoke it using the local variable, like this:
var eventHandler = MyEvent;
if (eventHandler != null)
{
eventHandler();
}
This question already has answers here:
Use of null check in event handler
(6 answers)
Closed 6 years ago.
I use a lot of custom events in my code, and have been declaring them like this
public delegate void ImageDownloadingEvent(Waypoint waypoint);
public event ImageDownloadingEvent ImageDownloading;
then firing them like this
if (ImageDownloading != null)
ImageDownloading(waypoint);
What I'd like to know is, is this bad practice? Or a bad way of doing things? If so, why? And what would be a better approach?
Thanks for any help, just trying to improve my coding skills
Well it's up to you to decide if events are the right pattern to use for a given scenario. Like anything, they can be used correctly or they can become a code smell. You can use a delegate of your own declaration, or one of the more generic ones like Func, EventHandler, or Action if you don't want to declare a new type for every event.
Your use of events is mostly correct. You want to copy the handler to a local. Eric Lippert has an explanation why on his blog.
So it becomes this:
var imageDownloading = ImageDownloading;
if (imageDownloading != null)
imageDownloading(waypoint);
The C# 6 compiler can do this for you like so:
ImageDownloading?.Invoke(waypoint);
In this case the compiler knows that it should make a local copy, first.
You can do it like that, although in a multi-threaded environment the way you are raising them has the potential for a race condition. Therefore, the recommended way to raise an event is actually
var handler = ImageDownloading;
if (handler != null) handler(waypoint);
With C# 6 that can be a bit more concise using the null-conditional operator:
ImageDownloading?.Invoke(waypoint);
Again, only relevant when multi-threading is a concern. Most code isn't built for that case anyway.
Then there is the question whether you want to use custom delegates for every event, or custom EventArgs for every event (and declare them as EventHandler<T>). That's entirely up to you, but it is sort of a convention in .NET.
I often see code like the following, and wonder if there is any reason for using a local variable for the event, instead of just using the event itself. Is there?
var handler = OnQueryComplete;
if (handler != null)
handler(this, new RepositoryEventArgs<T>(results));
Yes, absolutely - it makes the nullity check safe.
If you just have:
// Bad code, do not use
if (OnQueryComplete != null)
{
OnQueryComplete(this, ...);
}
then the last subscriber may unsubscribe between the check and the invocation, causing a NullReferenceException.
There are lots of options here:
Decide that you don't care about thread safety, even to the extent of it throwing an exception. (In many cases this may be reasonable, particularly if this is all your own codebase.)
Use an extension method to make this simple to achieve so the nullity check goes away anyway.
In C# 6, use the conditional null operator:
OnQueryComplete?.Invoke(this, ...);
Set up the event with a single empty handler which is never removed:
public event FooEventHander OnQueryComplete = delegate {};
You may also want to use Interlocked to make sure you've got the most recent value of the variable, to avoid memory model issues. See my blog post (including comments) for more discussion of this.
Microsoft's tutorial on events shows how to check an event for null before triggering it:
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
{ // Potential Race-condition at this point!
Changed(this, e);
}
}
But this leaves open a race-condition, as detailed in Eric Lippert's blog, where he writes that events should be triggered via a local event to avoid a race-condition:
protected virtual void OnChanged(EventArgs e)
{
ChangedEventHandler temp = Changed; // Local copy of the EventHandler
if (temp != null)
{ // Race condition avoided by local variable.
temp(this, e);
}
}
While this works, it has confused many developers who get it wrong, and don't put it in the locally-scoped event.
Another solution, from DailyCoding is to always initialize your event to have one empty handler, so a null-check is never needed:
// Set with empty delegate, will never be null
public event ChangedEventHandler Changed = delegate { };
protected virtual void OnChanged(EventArgs e)
{
// Neither Null-check nor local variable is needed; just trigger the event.
Changed(this, e);
}
This one makes a lot of sense, and is pretty simple.
However, since I see this technique so rarely mentioned online, I think there must be a reason why.
Is there a downside to initializing an event with an empty delegate like this?
You will see an absolutely tiny performance hit, but there are problems in more advanced cases, for example serializing and deserializing the class could lead to you losing the fake event handler, and the lack of a null check then throwing an exception.
It's a slight performance hit if the event would have been empty
If you ever write Changed = null in the class, it will break.
In Eric Lippert's blog article you posted, he says:
There are other ways to solve this problem; for example, initializing
the handler to have an empty action that is never removed. But doing a
null check is the standard pattern.
But before that he also says:
Removing the code around the call site [the null check] does not decrease the number of race conditions in the code [...]. Worse, doing so makes the race condition harder to detect by
shrinking the window in which the race can occur without eliminating
it.
This is because as he describes, it can still happen
Between the push of the delegate value [onto the stack] and the call to invoke it [...]
So basically, if you use an empty handler, you experience some performance loss (this seems to be the consensus here). So you're what you're gaining is readability, but most importantly: weird behavior will be more apparent. (I deduce this from less performance -> takes longer -> more likely to invoke stale handler)
So if you're fully aware that things like these can happen, and the null checking doesn't bother you, go for it. Or don't, if you don't want to.
-- If I define an event with an inital empty delegate I don't need to check for null
class MyClass
{
public event EventHandler<MyEventArgs> MyEvent = delegate { };
void SomeMethod()
{
...
MyEvent(); // No need to check for null
...
}
}
-- Otherwise I need to check for null
class MyClass
{
public event EventHandler<MyEventArgs> MyEvent;
void SomeMethod()
{
...
if (MyEvent != null) // No need to check for null
MyEvent();
...
}
}
What's the difference between these? In what cases one is better than another?
Thanks
The upvoted answer is dramatically wrong, I have to post an answer. Somebody is wrong on the Internet, can't come to bed just yet.
It is convenient but it doesn't come for free. The compiler has to generate a class for the anonymous method and the JIT compiler has to generate code for it. And that code always executes when you raise the event, whether or not a client has subscribed an event handler. The null check code also always executes, but that takes a lot less code and time.
This isn't a lot of code and a lot of time. The null check takes 2 machine code instructions and should execute in a single CPU cycle. The anonymous delegate takes about an order of magnitude more but that's still not a lot on a modern machine. Personally, I'm too old to be wasteful like that, two invariably is my choice.
Not in the least because that's the standard pattern, everybody recognizes it.
First one is applicable solution, but it has very very little performance penalty to call extra empty delegate.
Second solution is not thread safe (if it matters for you, of cause).
You should use following:
var handler = MyEvent;
if (handler != null )
handler(this, new MyEventArgs());
At our company we wrote an extension method which hooks onto most events, and checks if it's null before invoking.
We reduced this:
var handler = MyEvent;
if (handler != null)
{
handler(...);
}
to
MyEvent.SafeTrigger(...);