Why must someone be subscribed for an event to occur? - c#

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.

Related

Can I have only event without delegate?

I have a player with the event "shoot". If the player shoots a bullet I manually trigger the event. A different GameObject has a script where if listener and if event triggered, listener perform specific method. I'm new to events. I really don't need delegate, only event. I'm teaching myself programming from internet but everywhere is how to use event only with delegate.
Can I have only event without delegate and if yes how to declare event like this?
An event is a delegate with safety constraint.
You can only call an event from the class that holds it.
You can only register/unregister to an event from outside the class (only +=/-=)
You cannot pass an event as parameter
You can only wipe clean an event from the class that holds it (eventName = null)
Off topic : UnityEvent is not a real event, it is a class that contain a list of delegate (Action).
When you call an event (or a delegate), you should always check for nullity as you never know if the reference points to an object. You do not need this with UnityEvent since as I mentioned it is not real event and then if the collection is empty nothing happens.
public delegate void MyDel();
// The two following behaves the same
public MyDel myDel;
public Action myAction;
public event Action myEvent;
void Start(){
if(myAction != null){ myAction(); }
if(myEvent != null) { myEvent(); }
if(myEvent != null) { myEvent.Invoke(); }
}
those are same things, but the choice of whether one or the other is based on what you want to do.
Consider the following in another class:
void Start(){
refToClass.myAction = MyMethod;
refToClass.myEvent += MyMethod;
}
void MyMethod(){}
First case will remove all methods attached to the delegate and MyMethod is then the only one left to listen.
The event will not allow that, only +=/-= are allowed so you can only remove/add a method without affecting the others.
A delegate basically describes a function type. An event is a hook where registered functions matching a given function type are called when the event occurs.
Putting together these two simplified definitions, a delegate is also a descriptor for an event, therefore you cannot have an event without a related delegate.
Anyway, you are not forced to declare a new delegate for every event you declare. Instead, you can use any of the preexisting delegates such as EventHandler, EventHandler<TEventArgs> or even any of the Action overloads, choosing in the one that fits you best in each case.
I believe you technically can have events without a delegate as described in the answers here.
However, delegates are used to pass information from where the event was raised. Without it, the program doesn't know where the event was called from and what information to pass.
This is a good introduction and there are lots of examples on SO to help with niche cases. For now, if you're self-learning programming, I'd recommend you learn the pattern and get it working before worrying about why the delegate and event always come as a pair.
public delegate void ShootEventHandler(object sender, ShootEventArgs e);
public class ShootEventArgs
{
public ShootEventArgs(string s) { Text = s; }
public String Text {get; private set;} // readonly
}
It's commmon to pass this in sender and then new up the delegate you created. Where you want to call shoot, you'd have something like this.
var handler = this.Shoot; // Get the event you want to fire
handler?.Invoke(this, new ShootEventArgs("Bang")); // tell eveything interested "Bang"
GameObjects interested in the shoot event can subscribe to the information like so:
this.Player.Shoot += this.ShootHandler;
public void ShootHandler(object sender, ShootEventArgs e) // common to use e for event args
{
Console.WriteLine(e.Text); // print "Bang"
}
Yes, you can declare an event without declaring a delegate by using Action. Action is in the System namespace. So make sure you add "using System;" statement at the top of your code file.
//No parameter
delegate void _delegate1();
static event _delegate1 _event1;
//Parameterized
delegate void _delegate2(bool flag);
static event _delegate2 _event2;
this is equivalent to
static event Action _event1;
static event Action<bool> _event2;

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.

Handling an event that might not have any subscriber

If a class fires events in its methods, the class does not have to know what or who subscribes its events. It is not also important if there is any subscriber.
In the code below, if there is not any subscriber to OnTrigger event, an exception occures.
public class EventTrigger
{
public static void Main(string[] args)
{
(new EventTrigger()).Trigger();
}
public delegate void Delegate1();
public event Delegate1 OnTrigger;
void Trigger()
{
OnTrigger();
}
}
I can call the event like this;
if (OnTrigger != null)
{
OnTrigger();
}
But it seems weird to me, because the triggerer does not have to know about subscription.
My question is:
Do I have to check if the event reference is null whenever I use it.
If you initialize OnTrigger then you wont have to do the check.
e.g.
public event Action OnTrigger = delegate { };
Yes ´delegate { }´ instantiates a new object, which is why this allows you to omit the ´null´ check.
´delegate { }´ returns nothing, so if you want it to return a string (which you need if Delegate1 returns a string) then you simply add ´return "";´ e.g.:
public event Action OnTrigger = delegate { return string.Empty; };
One I should add is that it's bad practice to do this in order to avoid a null check, as it's a lazy mans hack. Some code can still set the event to null, ´OnTrigger = null´ will break your code. And when it comes to (de)serialization it wont work at all.
The triggerer doesn't have to know about the individual subscribers, but it does need to know about subscription. You have to either do the null check every time or use the work-around Simon suggested.

C# Create a Delegate that fires an event?

Is it possible to use Reflection is C# to fire an event? Say I have a situation like this:
public delegate void SomeEventHandler(object sender, BenArgs e);
class EventHub
{
public event SomeEventHandler SOME_EVENT;
public void fireEvent(String eventName)
{
SomeEventHandler evt = (SomeEventHandler) Delegate.CreateDelegate(typeof(SomeEventHandler), this, eventName);
evt.Invoke(null, null);
}
}
Meaning if I call
EventHub.fireEvent("SOME_EVENT")
then it makes the event hub fire SOME_EVENT? I've tried this and am just getting exceptions.
This is mostly a curiosity of mine, I know that in this case I could just as easily fire the event without reflection.
Assuming your current scenario, i.e.:
A field-like event.
The backing delegate-field has the same name as the event.
(this, EventArgs.Empty) are valid arguments to pass to the delegate.
You can do something like this (more argument validation required):
public void fireEvent(String eventName)
{
// Get a reference to the backing field
var del = (Delegate)typeof(EventHub)
.GetField(eventName, BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(this);
// Invoke the delegate, it's invocation-list will contain the listeners
if(del != null)
del.DynamicInvoke(this, EventArgs.Empty);
}
Usage:
var eHub = new EventHub();
eHub.SOME_EVENT += delegate { Console.WriteLine("SOME_EVENT fired.."); };
eHub.fireEvent("SOME_EVENT");
Now, you can generalize this idea with an extension method on object if you like, but all of this is a really bad idea. This problem can't be solved in the general case because one can't know how an event is "implemented." There could be arbitrary code inside the add and remove methods, and the logic to "fire" the event could also be just about anything. There might not even be a backing multicast delgate field to store the listeners.
In any case, trying to tell an object to fire an event is almost always a sign of a major design-flaw, IMO. If you still really do want this, it would be much better to declare a method like this in your class:
public void RaiseXXXEvent() { ... }

Need help understanding Events in C#

I'm a beginner in C# and having hard times understanding Events in C# .. The book i read (Illustrated C# 2008) gives an example about it , and there are few thing i need to ask about , so i will past the code here and point out the things i don't understand .
public class MyTimerClass
{
public event EventHandler Elapsed;
private void OnOneSecond(object source, EventArgs args)
{
if (Elapsed != null)
Elapsed(source, args);
}
}
class ClassA
{
public void TimerHandlerA(object obj, EventArgs e) // Event handler
{
Console.WriteLine("Class A handler called");
}
}
class ClassB
{
public static void TimerHandlerB(object obj, EventArgs e) // Static
{
Console.WriteLine("Class B handler called");
}
}
class Program
{
static void Main( )
{
ClassA ca = new ClassA(); // Create the class object.
MyTimerClass mc = new MyTimerClass(); // Create the timer object.
mc.Elapsed += ca.TimerHandlerA; // Add handler A -- instance.
mc.Elapsed += ClassB.TimerHandlerB; // Add handler B -- static.
Thread.Sleep(2250);
}
}
Ok, now the line after declaring the event here public event EventHandler Elapsed;
which is private void OnOneSecond(object source, EventArgs args) i know that the two line after it is to check if the event contains methods or not , but what is OnOneSecound for ? or when it's called ? or what it's named .. it's not event handler i guess right ? and what's the relationship between Elapsed and OnOneSecond ?
sorry for the newbie question .. and thanks in advance :)
the OnOneSecond method will be called internally by the MyTimerClass when it needs to invoke the event.
This is a common pattern used by most controls, including the microsoft ones.
Basically you dont need to be checking if the event is set in multiple places, you just do it in this one method then call this method internally to raise the event.
I tend not to pass the event args to the OnXXX method though, for example.
public event EventHandler<EventArgs> SomeEvent;
protected virtual void OnSomeEvent()
{
if (this.SomeEvent !=null)
{
this.SomeEvent.Invoke(this,EventArgs.Empty);
}
}
then to raise it
this.OnSomeEvent();
This is the method, that you call to raise the event safely.
the problem is, you can basically call
Elapsed(source, args)
but if there is noone connected to the event, this will raise a Reference Null exception. as the event is null, when nobody hears on it.
a better solution is, that you directly add a subscriber to the events. then you can safely call it directly. as there will be allways a subscriber.
public event Action<EventArgs> Elapsed = val => { };
(note that with the = its directly assigned. val => { } is a Lambda expression, that defines a empty subscriber.)
Also, look into the Reactive Framework for .net
if you want to do a lot of event stuff, this is the correct solution for it.
That allows you to manually fire the events from thein the class.
That is the standard pattern for raising internal events that's why it is private.
OnOneSecond is just a helper method defined to raise the event. You can use events without such methods, it is just an established pattern to wrap the if (Elapsed != null) check in a method with a name that starts with On...
Technically you could just use Elapsed(source, args) instead of OnOneSecond(source, args), but this will throw NullReferenceException if there are no listeners registered.

Categories

Resources