-- 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(...);
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();
}
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.
From this question (and others) there's this example of snapshoting the event handler value before invoking:
var tmp = _myEventHandler;
if(tmp != null) {
tmp(sender, args);
}
However, if I pass in the event handler and args into a function does this do the same thing?
protected void Invoke(MyEventHandler handler, MyEventArgs args)
{
if (handler != null)
handler(this, args);
}
I would say yes, but after thinking about this I don't know if it is the same - like could an optimization process inline this function and remove the snapshot variable?
It indeed does the same thing. The code is simply checking that the event handler is non-null and hence available for raising. This code is no different for a field / parameter / local. The C# compiler or JITer cannot inline this in such a way that the temporary is removed because it would change the semantics of the program.
The race condition is explained in your other links, such as Marc Gravell's answer.
As #JaredPar points out, your code effectively does the same thing. However, it violates the standard event conventions for .NET, which recommend the following:
protected virtual void OnAlarmRaised(AlarmRaisedEventArgs e)
You are free to violate the pattern, but doing so goes against the grain for minimal (if any) benefit.
Why would a 'public event EventHandler cccc' be null?
I have a class that's
public class Builder
{
public event EventHandler StartedWorking;
public Builder()
{
// Constructor does some stuff
}
public void Start()
{
StartedWorking(this, eventargobject); //StartedWorking is null --
}
}
This seems straightforward and something I do all the time? Am I missing something obvious or is there something that could cause this?
EDIT:
Does this mean that if I fire an event that is not subscribed to in a client class I have to check that it is not null?
EDIT-2:
I guess I'd never had events that were never not subscribed to and hence never ran into this --
You learn something new every day
Sorry about the seemingly stupid question....
The event handler will be null unless somebody has subscribed to the event. As soon as a delegate is subscribed to the event, it will no longer be null.
This is why it's always suggested to use the following form for raising events:
public void Start()
{
var handler = this.StartedWorking;
if (handler != null)
{
handler(this, eventArgObject);
}
}
This protects you from a null exception if there has been no subscribers.
As others have already said, it's null because there are no subscribers.
To answer your edit: Yes, you should always check an event for null before triggering it. However, if you just do a plain if(StartedWorking != null){...} you risk a race condition, because it's possible for a subscriber to unsubscribe after the null check but before you trigger the event. Because of this, you should always use this pattern when checking events for null:
protected void OnStartedWorking()
{
EventHandler localEvent = StartedWorking
if(localEvent != null)
{
localEvent(this, EventArgs.Empty);
}
}
This prevents the race condition by taking a copy of the event first so the subscribe list is fixed at the point of copying.
There's more infomration about publishing events on MSDN: How to Publish Events that Conform to .NET Framework Guidelines
(This works because in .net the MultiCastDelegate class in imutable, so any attempt to change the subscriber list on the event won't effect the copy you have made)
If you haven't hooked any event subscribers up to your StartedWorking event, then it will be null. That is how .NET events works.
This article, among other things, demonstrates that you should check for null before invoking an event. This other question and answer demonstrates how you can create events in a way that avoids the null check (basically by adding an empty handler always).
Don't you need to assign a function ?
StartedWorking += new EventHandler(afunction);
void afunction(object sender, EventArgs e)
{
DoSomething();
}
Evil or not evil?
public static void Raise(this EventHandler handler, object sender, EventArgs args)
{
if (handler != null)
{
handler(sender, args);
}
}
// Usage:
MyButtonClicked.Raise(this, EventArgs.Empty);
// This works too! Evil?
EventHandler handler = null;
handler.Raise(this, EVentArgs.Empty);
Note that due to the nature of extension methods, MyButtonClicked.Raise will not throw a NullReferenceException if MyButtonClicked is null. (E.g. there are no listeners to MyButtonClicked event).
Evil or not?
Not evil. I wish events worked this way by default. Can someone explain why an event with no subscribers is null?
You can always declare your events like this (not that i recommend it):
public event EventHandler<EventArgs> OnClicked = delegate { };
That way they have something assigned to them when you call them, so they don't throw a null pointer exception.
You can probably get rid of the delegate keyword in C# 3.0...
Don't forget to use [MethodImpl(MethodImplOptions.NoInlining)], else its possible that it isn't thread safe.
(Read that somewhere long ago, remembered it, googled and found http://blog.quantumbitdesigns.com/tag/events/ )
Coming from a java background this has always seemed odd to me. I think that no one listening to an event is perfectly valid. Especially when listeners are added and removed dynamically.
To me this seems one of C#'s gottchas that causes bugs when people don't know / forget to check for null every time.
Hiding this implementation detail seems a good plan as it's not helping readability to check for nulls every single time. I'm sure the MSFTs will say there's a performance gain in not constucting the event if no one is listening, but imho it is vastly outweighed by the pointless null pointer exceptions / reduction in readability in most business code.
I'd also add these two methods to the class:
public static void Raise(this EventHandler handler, object sender)
{
Raise(handler, sender, EventArgs.Empty);
}
public static void Raise<TA>(this EventHandler<TA> handler, object sender, TA args)
where TA : EventArgs
{
if (handler != null)
{
handler(sender, args);
}
}
Why would it be evil?
Its purpose is clear: It raises the MyButtonClicked event.
It does add a function call overhead, but in .NET it will either be optimized away or pretty fast anyway.
It is slightly trivial, but it fixes my biggest complaint with C#.
On the whole, I think it's a fantastic idea, and will probably steal it.
I wouldn't say it's evil, but I'm interested in how your extension method fits in with the
protected virtual OnSomeEvent(EventArgs e){ }
pattern and how it handles extensibility via inheritance. Does it presume all subclasses will handle the event instead of override a method?
Although I wouldn't describ it as evil, it still has a negative implication, as it adds unnecessary overhead:
When calling
myEvent.Raise(this, new EventArgs());
the object EventArgs is initialized in all situations, even if no-one subscribed to myEvent.
When using
if (myEvent!= null) {
myEvent(this, new EventArgs());
}
EventArgs is only initialized if someone subscribed to myEvent.
Throwing an exception when there are no handlers is not really preferable by the most. If it does not have an handlers it is better to be empty rather than null.