I just realized I can add an event handler in two ways:
Consider an event handler like so:
private void MyEventHandler()
{}
Method 1: Instantiate a new delegate
MyObject.MyEvent += new Action(MyEventHandler);
Method 2: Add event handler without instantiating a new delegate
MyObject.MyEvent += MyEventHandler;
Is there any difference in between these two implementations that should be considered?
There is no difference, the generated IL is the same. The shorter form was introduced in .net/c# 2.0 as a convenience function, although Visual Studio still does the first form on Tab Completion.
See this question for some more info.
I believe that while you can unsubscribe from the second, you'd not be able to unsubscribe from the first.
That would be a pretty important distinction. There is really nothing to be gained by wrapping it in an Action in any case.
update
Okay, I think I misunderstood what you were doing. If the event is declared as
public event Action MyEvent;
then the two subscriptions are equivalent, the second being shorthand for the first.
There are actually other ways to add event handlers:
MyObject.MyEvent += delegate { MyEventHandler(); };
MyObject.MyEvent += () => MyEventHandler();
In these cases, you would not be able to unsubscribe. In these examples, the delegates are calling the handler method, but usually when employing this method it is to avoid having to create separate handler methods -- the handler code goes right in the anonymous method.
Related
I'm not new to C#, but events is one of the most confusing topics I confront in the language.
one of the questions is: where should I assign the event handler to the event, or the question in other form: why most events are raised in the subscriber constructor? what does it mean?
like this example (taken from the book Mastering Visual C# )
public ReactorMonitor(Reactor myReactor)
{
myReactor.OnMeltdown +=
new Reactor.MeltdownHandler(DisplayMessage);
}
Raise = generate. Events are not raised in the subscriber constructor. The subscriber does not raise events at all. The event source raises/generates events, and subscribers subscribe to, receive, and handle them.
Events in c# are nothing more than function pointers, i.e. a variable that contains a pointer (or list of pointers) to a function that matches a specific signature (typically Action<object,EventArgs>). Or in the words of this MSDN article:
Delegates are like C++ function pointers but are type safe.
When you subscribe to an event, you are essentially saying "Store the address of my function. When X happens, please call it (along with any other function whose address is stored)."
Thus the code
myReactor.OnMeltdown += Meldownhandler;
can be read as
objectThatRaisesEvents.FunctionPointer = MyHandler;
Notice that MyHandler is not followed by parentheses. If it were MyHandler() that means you are invoking the function, the value of the expression MyHandler() is actually the return value of the function; MyHandler by itself doesn't invoke the function or return its value but instead returns the address of the handler itself. So the above line of code takes the address of MyHandler and stores it in a variable named FunctionPointer.
When the object that raises events invokes FunctionPointer() it is telling c# to obtain the address of the function stored in FunctionPointer and invoke it.
So it is really calling MyHandler() indirectly. Thus these two lines do exactly the same thing:
objectThatRaisesEvents.FunctionPointer();
MyHandler();
Also notice the += in your example. In c# that is the equivalent of
objectThatRaisesEvents.FunctionPointer =
objectThatRaisesEvents.FunctionPointer + MyHandler;
We typically use that syntax because there might be several handlers that subscribe to an event. += has the effect of appending our handler to the list. You could use = instead, but it would unsubscribe any existing handlers.
To answer your question-- when should you subscribe to events? That is a very broad question, but typically
In an ASP.NET web page, you'd subscribe during the Init event.
In a Windows Form, you'd subscribe in the InitializeComponent method.
There are many other contexts of course... the bottom line is you should subscribe before you need to receive notifications of occurrences of the event.
The event is one of the standard features of .NET Framework built using delegate model implementing the Observer design pattern.
https://msdn.microsoft.com/en-us/library/edzehd2t(v=vs.110).aspx
https://en.m.wikipedia.org/wiki/Observer_pattern
Where you subscribe to the event depends on the business rules, but most of the time you want to subscribe at the earliest possible moment which is usually the constructor of the class interested in the handling of the event.
When events should be raised on the other hand depends on what you are trying to communicate to the subscribers if it is a notification of the state change then you raise an event as soon as state is changed.
An event is a message sent by an object to signal the occurrence of an
action. The action could be caused by user interaction, such as a
button click, or it could be raised by some other program logic, such
as changing a property’s value.
It is possible to execute the following code from multiple threads simultaneously.
this._sequencer.Completed += OnActivityFinished;
Is it thread safe to add delegate to an event handler from multiple threads?
Is it thread safe to remove delegate to from event handler from multiple threads?
What is the simplest and maintainable way of making this thread safe?
If you don’t specify your own event add/remove handlers, the C# compiler generates this add handler (reconstructed by .NET Reflector):
public void add_MyEvent(EventHandler value)
{
EventHandler handler2;
EventHandler myEvent = this.MyEvent;
do
{
handler2 = myEvent;
EventHandler handler3 = (EventHandler) Delegate.Combine(handler2, value);
myEvent = Interlocked.CompareExchange<EventHandler>(ref this.MyEvent, handler3, handler2);
}
while (myEvent != handler2);
}
and a remove handler that looks the same but with Delegate.Remove instead of Delegate.Combine.
Notice the use of Interlocked.CompareExchange? This prevents a race condition between updating the event’s backing field and reading from it. Thus, it is thread-safe.
It depends on the implementation of the event, to be honest.
The field-like events generated by the C# compiler are thread-safe, but if it's a custom event, who knows?
Note that in a multi-threaded app you should expect a race condition between adding/removing a handler and the event firing... for example, the event may start to fire, you could then unsubscribe, and your handler would still be called after that unsubscription.
for field-like events adding/removing of handlers is thread-safe. From spec:
When compiling a field-like event, the compiler automatically creates storage to hold the delegate, and creates accessors for the event that add or remove event handlers to the delegate field. In order to be thread-safe, the addition or removal operations are done while holding the lock (§8.12) on the containing object for an instance event, or the type object (§7.6.10.6) for a static event.
However it is true for C# 3.0 and lesser, in C# 4.0 compiler generates lock-free implementation using Interlocked routines (but spec remains the same - bug?)
In custom implementations no one can tell exactly... except maybe the author of code :)
So if I do something like this on my event declaration:
public event MyDelegate MyEvent = delegate { };
I read that this makes null checks redundant, that there will be a no-op subscriber.
I'm curious how this works under the hood. What exactly happens and is this a good practice, or should I stick with usual null check before firing the event handler?
The null checks aren't tricky because of an extra if - they are tricky because they're unreliable in a multi-threaded environment.
It's a trade-off. If you expect that the event will only have 0-1 delegates, using a (safe) null-check is probably better. If you expect to have multiple subscribers that keep subscribing and unsubscribing, you're better off with the "null-delegate". It does mean an extra delegate in the call chain, but that's usually cheap enough for most uses of events in .NET.
You wouldn't want to use it on e.g. a control that has 50 different events most of which never have a subscriber, or your behaviour changes based on whether there is a subscriber or not.
As for what happens under the hood, well... nothing. This does no magic whatsoever. The trick is in how += works on events / delegates.
If you have a null event, and use +=, it simply assigns a new delegate to the event. If there already is a delegate, it will create a new delegate, which is a combination of the previous delegate and the new one. If you use that null-delegate, it simply means that there is always some delegate to combine. The usual code for invoking an event can look something like this:
var ev = Click;
if (ev != null) ev();
This means that if there is no subscriber to the event, there is no invocation. In the null-delegate case, the code is further simplified to
Click();
This always means a delegate invocation - at the very least, your null-delegate is invoked. Sure, it doesn't actually do anything, but you keep the delegate invocation overhead. Again, this is rarely a problem, but there are cases where this is unacceptable.
I would like to confirm something - when I register a method as a subscriber to an event the long way, like so:
_serviceContext.ReadingEntity += new EventHandler<ReadingWritingEntityEventArgs>(_serviceContext_ReadingEntity);
I need to un-register that method from the event's subscription if I don't want it to continue to be called when the event is fired, like this:
_serviceContext.ReadingEntity -= new EventHandler<ReadingWritingEntityEventArgs>(_serviceContext_ReadingEntity);
When I register a delegate as a subscriber to an event, like so:
public guy ThisMethod()
{
_serviceContext.ReadingEntity += delegate(object sender, ReadingWritingEntityEventArgs e)
{
};
}
There is no way to un-register that delegate from the subscriber list from that method. So I am assuming that the scope of this registration is limited to the method in which it's registered - i.e. if the _serviceContext.ReadingEntity event was fired in a method called by ThisMethod, this registration would be already expired and the code inside the delegate would not run. Is this correct?
Thanks!
p.s. I realize that the first "long" way of registering an event handler also has scope limitations, but I'm a bit hazy on that. My main question, however, is whether or not the delegate registration will live on outside of the method above.
Once you subscribed a delegate this way (you can unsubscribe using -= operator if you cache the delegate variable somewhere) you can't remove it from subscribers list and it will be invoked every time event rises until publisher is alive. Moreover this subscription will prevent any subscriber class (class which contains the method you subscribed to event) from garbage collection until publisher is alive (unless you use a static method).
To give some clarity, there is no "anonymous" methods in IL code. All your delegates and lamdbas are translated into static/instance methods and closure classes (depends on whether they use instance members/function parameters).
You can unsubscribe a delegate if you keep a reference to it.
EventHandler<ReadingWritingEntityEventArgs> aDelegate = delegate(object sender, ReadingWritingEntityEventArgs e)
{
};
_serviceContext.ReadingEntity += aDelegate;
_serviceContext.ReadingEntity -= aDelegate;
If you do not do it this way, there is no way to unsubcribe. The scope is not limited to the method in which it was registered. It will be registered for the lifetime of the event.
Following on from this post - what are the disadvantages when using the -= then += approach suggested when I only ever want one handler event to fire?
_value.PropertyChanged -= _handlerMethod;
_value.PropertyChanged += _handlerMethod;
This doesn't guarantee that there is only one handler fired.
Another location could, potentially, subscribe your handler to your event multiple times. In this case, you will only remove the first handler call.
By inspecting the invocation list of the event, you could guarantee this behavior, if you truly only want a single handler to be subscribed at a time.
If you really want only one handler to execute, then you may want to use a settable property of the appropriate delegate type instead of an event. Only one delegate will be stored; you can execute the delegate the same as you would the event handler.
The idea here is that the -= operator is not going to do anything if your event handler is not assigned.
I don't personally like this approach, I think you should really aim to refactor your code so that you know that the event handler is assigned only once.
The disadvantages would be:
- possibility of race condition, if your app is multithreaded and the event gets fired when the handler is not assigned
- I am also not sure what happens when you run _value.PropertyChanged -= _handlerMethod when two copies of the handler are already assigned.
- messy code - obviously its not clear from the code which class and when is listening to the event