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.
Related
Action1
triggers Event1
Event2
in this order.
Action2 also triggers Event2.
I need to execute a method after Event1 is triggered AND COMPLETED.
How would I achieve this in C#/.NET?
The key is that I need to execute that method when the event is completed, because only then I have access to certain properties of an object.
I was thinking of adding a variable globally at class level and assign it a value inside Event1 handler.
Then checking inside Event2 handler if the variable was initialised, which means we are at a stage where Event1 was completed. And then inside Event2 handler adding my method.
This doesn't seem to work because Event2 is triggerred extremely often when Action2 is executed (an action I don't care about) and I get a stack overflow error message.
Is there a good way to actually make this work?
Can(how) I do something like override the library and add a new event (that does nothing) triggered when an existing event is completed; then I would use the new event just to attach a handler to it and put my method there.
These events and actions are inherent to a framework so I don't have much control over them as their definition is hidden inside .net libraries.
So I'm interested in some general principles and tricks and these are the limitations/setbacks.
Some sample code can be found here: https://stackoverflow.com/questions/41969955/how-to-use-invoke-to-call-a-method-after-an-event-was-finished
Event handling is by its nature synchronous (assuming somebody doesn't use async void or start their own thread in a handler) so the following code:
Event1?.Invoke();
//Do stuff after Event1
Will already do what you are asking. If you need to wait for some asynchronous task that is kicked off by a handler of Event1 then you will need to do that apart from the event invocation process.
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.
I recently attended a interview in C# where i was asked a question about Events and delegates in C#
The person asked me when a event say button gets clicked, which gets called first event or delegate?
Does the delegate calls the event or the event calls delegate?
Can we have a event without a delegate in c#?
The person asked me when a event say button gets clicked, which gets called first: the event or the delegate?
When you open a door, which gets opened first: the door or the doorknob?
Huh?
That question doesn't make any sense. You open a door with a doorknob, but you don't open a doorknob.
What does it mean to "call" an event? Events aren't things that you call. Events are things that you raise. Raising an event is identical with calling the delegate.
Does the delegate calls the event or the event calls delegate?
Does the door open the doorknob, or does the doorknob open the door?
Again, the question doesn't make sense. A doorknob is not something that can be "opened", and the doorknob does not open the door -- you open the door, by holding the doorknob.
Does the delegate call the event? No; events are not things that can be "called". Does the event call the delegate? No, the code that is raising the event calls the delegate.
Can we have a event without a delegate in c#?
Yes, in the sense that the delegate reference associated with an event can be a null reference. But every event is associated with a delegate type, and somehow has associated with it a reference to a delegate.
The whole set of questions indicates to me that the questioner does not have a very good understanding of the relationship between events and delegates. A good way to think about it is that an event is just a property that contains a reference to a multicast delegate. Whereas a property has special methods that get and set the value of the property, an event has special methods that add and remove delegates to the multicast delegate.
Events are a concept which utilize delegates as a means to call methods that have subscribed to them.
Events themselves are not called. When a piece of code raises an event, it will call each of the subscribed methods by invoking the delegates.
Events are raised, delegates are called. So when the button is clicked, a buttonClick event is raised, meaning that each delegate subscribed to the event will be called, according to the subscription order.
An event is simply a code construct implemented in .NET as a multi-cast delegate.
When an event is "raised" (which can only be done by code in the same class as the event; event raising must happen within "protected" scope), the delegates are invoked one at a time, in a synchronous fashion but not necessarily in any deterministic order. The event IS the delegate, so when the event is raised for a button being clicked, the delegates are invoked by the runtime, which has received the Windows message that the user clicked on the GUI area for the button.
The statements "the event is raised" and "the delegates are invoked" are equivalent statements; it's like asking "which comes first, the chicken or the gallus domesticus?".
Now, events often cascade, especially when we're talking about UI. There is a MouseUp event, invoked when the mouse button is released, which can fire one or more other events such as MouseClick, MouseDoubleClick, DragDrop, etc. You may not attach a handler to the MouseUp event, but there is built-in logic behind the scenes of MouseUp to raise the MouseClick event which you DO handle. So, in this sense, you could say that the MouseUp event "comes first" and calls the MouseClick handler delegate.
This page bubbled up on top of Google results, so below is something you might find useful if you also land here. Multi-cast delegates ARE called (see MSDN) in deterministic order on one thread, in the order of assignment. This assignment will involve an array of some sort, and it would be illogical for the indices to fill up out of order.
public partial class Form1 : Form
{
ob<Control>ob1;
ob<Control>ob2;
ob<Control>ob3;
public Form1()
{
InitializeComponent();
ob<Control>.setup(button1);
ob1 = new ob<Control>(1, true);
ob2 = new ob<Control>(2, false);
ob3 = new ob<Control>(3, false);
}
public class ob<T> where T : Control
{
int ndx;
Boolean isSentinel;
static Boolean dontdostuff;
static T c;
public static void setup(T c) {ob<T>.c = c;}//an argument less from constructor, useful for many objects (more likely to be menuitems)
public ob(int ndx, Boolean isSentinel)
{
this.ndx = ndx;
this.isSentinel = isSentinel;
c.Click += new EventHandler(click);
}
void click(object sender, EventArgs e)
{
if( isSentinel)
{
if (MessageBox.Show("ob" + ndx + " asks: short circuit subsequent delegate calls?", "", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
{
dontdostuff = true;
return;
}
else
{
dontdostuff = false;
}
}
else
{
if( dontdostuff) return;
}
MessageBox.Show("ob" + ndx + " doing stuff in order of handler addition", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
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.
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