Reputation: 109
I can't really understand what is this null testing thing for when raising an event.
Say i have this code.
class ballClass
{
public event EventHandler BallInPlay;
public void onHit()
{
if (BallInPlay != null)
{
BallInPlay(this, new EventArgs());
}
else
{
MessageBox.Show("null!");
}
}
}
and I want to to raise a BallInPlay even when the onHit() method is triggered.
right now it shows me that the BallInPlay IS null. how or with what should i "fill" it for it to work?
Thanks!
Upvotes: 5
Views: 5515
Reputation: 1499660
You need to subscribe to the event with a handler. For example:
BallClass ball = new BallClass();
ball.BallInPlay += BallInPlayHandler;
// Now when ball.OnHit is called for whatever reason, BallInPlayHandler
// will get called
...
private void BallInPlayHandler(Object sender, EventArgs e)
{
// React to the event here
}
For more information, you may want to read my article on events and delegates.
Note that I've fixed the casing of BallClass
and OnHit
above - it's a good idea to use the standard .NET naming conventions to make your code fit in better with the code around it, and to make it more readable for others.
One thing to note: the nullity check you've got at the moment isn't thread-safe. The last subscriber could unsubscribe after the if
but before the invocation. A thread-safe version would be:
public void OnHit()
{
EventHandler handler = BallInPlay;
if (handler != null)
{
handler(this, new EventArgs());
}
else
{
MessageBox.Show("null!");
}
}
This wouldn't be guaranteed to use the latest subscribers (as there's no memory barrier involved) but it is guaranteed not to throw a NullReferenceException due to race conditions.
Upvotes: 7
Reputation: 20314
If there are no event handlers assigned to the event, the event is null. Think of an event like a List, when there are no items in the list the value of the event becomes null
.
Attempting to invoke the event when there are no event handlers assigned to it will raise a NullReferenceException.
The null check prevents the NullReferenceException.
If you want BallInPlay to work you need to add an EventHandler
.
Your code will be something like this:
BallInPlay += new EventHandler(YourFunctionNameGoesHere);
Upvotes: 2
Reputation: 84725
BallInPlay(this, new EventArgs());
The reason for the null
check before triggering the event will become obvious once you realise that the above line of code actually gets compiled as if you had written the following:
BallInPlay.Invoke(this, new EventArgs());
// ^^^^^^^
And as we all know, it's a bad idea to call a method on a null
reference. That's why you need to check that BallInPlay != null
first.
Additional suggestions:
Use EventArgs.Empty
instead of new EventArgs()
.
You could get around the check for null
if you initialized BallInPlay
as follows:
public event EventHandler BallInPlay
= delegate { }
;
This works because now, there's always an "empty" handler method subscribed to this event. Thus you have a guarantee that the event delegate is no longer null
after initialization. (Some people might consider this slightly inefficient.)
You can always subscribe or unsubscribe event handlers with the +=
or -=
operators on the BallInPlay
event; for example:
ball.BallInPlay += (sender, e) => { /* react to the triggered event */ };
I think your onHit
(or, rather, OnHit
if we're adhering to the usual conventions found in the .NET world) method should not be public, because this counters the whole purpose of events. Events are actually delegates, but with some added restrictions. One such restriction is that only the class defining the event can invoke ("trigger") it. Delegates, on the other hand, can be invoked by anyone. Thus, if you make onHit
public, thereby allowing anyone to trigger your event, you could just as well have defined BallInPlay
as a delegate, i.e. without the event
keyword.
A thread-safe implementation of your onHit
event trigger method is shown below. Note that a local copy of the event handler delegate is used inside the method. This is to make sure that the event handler won't be modified (e.g. by another thread) between the check for null
and the invocation.
protected virtual void OnHit()
{
EventHandler handler = BallInPlay; // use a local copy of the event
if (handler != null) // for better thread-safety!
{
handler(this, EventArgs.Empty);
}
}
Upvotes: 1
Reputation: 60684
The thing here is that if zero listeners are registered to listen to this event get raised, the event is null. If one or more listeners are registered it will have a value.
That means that if zero listeners are registered, and you try to raise the event without performing the null check, your program will throw an exception.
Upvotes: 10
Reputation: 62093
The null test is ther because if NOONE IS LISTENING to the event, the event object that you swuold call is actually null. So, without subscribers you would get a null pointer exception.
Upvotes: 2
Reputation: 15999
The null test is to determine whether or not anything is listening to the event. Once something attaches an event handler, BallInPlay will no longer be null
Upvotes: 1
Reputation: 3108
BallInPlay += new EventHandler(myFunc);
public void myFunc(object sender, EventArgs e)
{
MessageBox.Show("Woho \o/");
}
Upvotes: 0