How does C# eventhandler work internally? - c#

I guess C# eventhandler has a list of listeners and it loops thru the list when sending a message. My question is how does this works in internally. Does it make a copy of the list before looping it thru and if so, what happens if someone unregister itself after the list has been copied but it has not yet received the message.
Will it still get the message even do it has unregister itself?

A delegate is immutable, so when you are invoking a delegate the list of subscribers is known and fixed. Subscribing or unsubscribing replaces the delegate that underpins the event.
This does indeed mean that in a multi-threaded scenario you can receive an event after unsubscribing, because either:
the delegate was already in the process of being invoked
a snapshot of the delegate had already been obtained for the purpose of invoking
by 2, I mean the usual pattern (to prevent a null-ref during invoke):
var handler = SomeEvent;
// <===== another thread could unsubscribe at this point
if(handler != null) handler(sender, args); // <== or part way through this invoke
// (and it either case, have the event trigger even though they think they have
// unsubscribed)
For that reason, if you are coding complex multi-threaded code with events, you should code defensively such that the event firing after you think you have unsubscribed is not a problem.
These nuances do not really impact single-threaded code.

Related

Where should events be raised?

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.

No-op subscriber to events in C# - null checking redundant

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.

Local Reference to EventHandler Before Invocation [duplicate]

This question already has answers here:
C# Events and Thread Safety
(15 answers)
Closed 9 years ago.
So i've read around that instead of calling a event directly with
if (SomeEvent != null)
SomeEvent(this, null);
i should be doing
SomeEventHandler temp = SomeEvent;
if (temp != null)
temp(this, null);
Why is this so? How does the second version become thread safe? What is the best practice?
IMO, the other answers miss one key detail - that delegates (and therefore events) are immutable. The significance of this is that subscribing or unsubscribing an event handler doesn't simply append/remove to a list - rather, it replaces the list with a new one with an extra (or one less) item on it.
Since references are atomic, this means that at the point you do:
var handler = SomeEvent;
you now have a rigid instance that cannot change, even if in the next picosecond another thread unsubscribes (causing the actual event field to become null).
So you test for null and invoke it, and all is well. Note of course that there is still the confusing scenario of the event being raised on an object that thinks it unsubscribed a picosecond ago!
Events are really syntactic sugar over a list of delegates. When you invoke the event, this is really iterating over that list and invoking each delegate with the parameters you have passed.
The problem with threads is that they could be adding or removing items from this collection by subscribing/unsubscribing. If they do this while you are iterating the collection this will cause problems (I think an exception is thrown)
The intent is to copy the list before iterating it, so you are protected against changes to the list.
Note: It is however now possible for your listener to be invoked even after you unsubscribed, so you should make sure you handle this in your listener code.
Best practice is the second form. The reason is that another thread might null or alter SomeEvent between the 'if' test and the invocation.
Here is a good write up about .NET events and race conditions with threads. It covers some common scenarios and has some good references in it.
Hope this helps.

C# Is it thread safe to subscribe Same event handler for all Objects

I have a situation in my project where i have connect to multiple server and listen for events. Whenever a event received from the server, Handler should add the event to the common queue for processing. All connections should add received events to the queue.
foreach(var item in collection)
{
Connection c = new connection(item);
c.start();
c.EventReceived+=new EventHandler(myHandler);
list.add(c);
}
protected void myHandler(eventArgs)
{
//add it to the concurrent queue
}
Here i doubt that whether it can be able to handle those events without any threading issues. Please let me know if you have any patterns or built in APIs to handle this safely.
Thread-safety always needs a context - a from what.
If you mean the +=
For the +=, that depends on how the event is implemented. If it is implemented as a field-like event, i.e.
public event SomeEventType EventReceived;
then yes: it is thread-safe. The specification requires that the accessors for field-like events are thread-safe, although the implementation can vary (for example, the MS compiler used to use lock(this) or lock(typeof(DeclaringType)), however it now uses Interlocked instead).
If the event is implemented manually, i.e.
public event SomeEventType EventReceived {
add { ... }
remove { ... }
}
Then the thread-safety is defined entirely by the add/remove implementations.
If you mean the invoke
Then that is thread-safe since delegates are immutable, but note that it all happens on the single thread that invokes the thread. However, a common mistake is to introduce a race condition in a null test:
if(EventReceived != null) EventReceived(this, someArgs);
The above is not thread-safe, since technically the value of EventReceived can change after the test. To ensure this does not error, it should be:
var handler = EventReceived;
if(handler != null) handler(this, someArgs);
If you mean the handlers
Then the thread-safety is defined entirely by the individual handlers. For example, in UI applications it is the handlers that must check for, and switch to, the UI thread.
Quoting from C# 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.
Bottom line is if the EventReceived is field like event(non custom implementation) then its thread safe!
Update
Current implementation uses Interlocked for thread safety

Clearing C# Events after execution?

Say I have the following code:
public event EventHandler DatabaseInitialized = delegate {};
//a intederminant amount of subscribers have subscribed to this event...
// sometime later fire the event, then create a new event handler...
DatabaseInitialized(null,EventArgs.Empty);
//THIS LINE IS IN QUESTION
DatabaseInitialized = delegate {};
Will this clear out the subscribers, replacing it with new empty default? And, will the event notify all subscribers before they get cleared out? I.E. Is there a chance for a race condition?
Yes it will clear it out. And because events fire syncronously in the same thread there shouldn't be race condition.
My advice: when in doubt, write a small test application and... well, test it.
UPDATE: I tested it before posting. (In response to minuses.)
To unsubscribe from the event use event-=delegate, so you're sure that resource is free. Even if by official Microsoft documentation it's not necessary, in my own experience, especially on a large scale complex project, unnecessary events suscribers are source for memory leaks. So unsubscribe from them explicitly.

Categories

Resources