Here is my question: if I want to ensure, that a handler is subscribed only once, is it correct to subscribe in this way:
x.Event -= Handler;
x.Event += Handler;
Idea is "try unsubscribe, even if we were not subscribed", then subscribe when we are 100% not subscribed.
Is this idea correct, and if not - why? Googled it for some time, cannot seem to find the answer myself.
So long as you do that everywhere you're subscribing that handler, it should be fine. But if you subscribe 100 times and then run that code, you're still going to be left with 100 subscriptions.
(I'm assuming you're only using a single thread, by the way. There's a race condition if two threads execute that code at the same time... they could both unsubscribe an then both subscribe, leaving two active subscriptions.)
What you have will not throw any exceptions, so it will work as intended -- but it's not very clear code.
I would very much prefer a test with a boolean flag instead:
if(!subscribed) {
x.Event += Handler;
}
Related
Is there a problem if I subscribe to the same event three times with the eventHandler?
e.g.
a.SomethingChanged += new EventHandler(ChangeHandler);
a.SomethingChanged += new EventHandler(ChangeHandler);
a.SomethingChanged += new EventHandler(ChangeHandler);
Does this cause ChangeHandler to be invoked 3 times instead of 1? What is best way to handle this?
Note that these redundancies are not together but different areas of code paths.
Similary, is there an issue with unsubscribing from an event that is not registered?
e.g.
a.SomethingChanged -= new EventHandler(ChangeHandler); //ChangeHandler was never registered
If you subscribe to an an event more than once then your handler will be called the corresponding number of times - in your example three.
Whether this is a problem or not depends on what your event handler does, but I'm assuming that you don't want it to be called multiple times.
There is no problem in unsubscribing from an event that you haven't subscribed to.
So if you're not sure what state your application is in (though you really should be) you can have:
a.SomethingChanged -= ChangeHandler;
...
a.SomethingChanged += ChangeHandler;
(Note: the new EventHandler(...) is syntactic sugar and can be omitted)
Is there a problem if I subscribe to the same event three times with the eventHandler?
Nope, it will just add the event handler three times.
Does this cause ChangeHandler to be invoked 3 times instead of 1?
Yes.
What is best way to handle this?
That depends on what you want; which you haven't specified. If you want a way to add an event handler if and only if it hasn't already been added, then just remove the event handler and then add it again:
a.SomethingChanged -= new EventHandler(ChangeHandler);
a.SomethingChanged += new EventHandler(ChangeHandler);
Is there an issue with unsubscribing from an event that is not registered?
No, it will just do nothing.
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.
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.
How to know that DataTable is already subscribed to OnRowChanged or OnColumnChanged events ?
I am facing a issue with many notifications in my app ? so I wanted to put a check and want to subscribe table only once ??
Outside of the declaring class it is deliberately tricky to see what is subscribed, since that is generally not something you need to know.
Depending on the scenario, either get very good at tracking when you subscribe, or simply unsubscribe first (which does nothing if you aren't subscribed):
foo.OnSomeEvent -= SomeHandler;
foo.OnSomeEvent += SomeHandler;
As long as the handler and target-instance (for non-static handlers) is the same this will:
if subscribed, the net result is that you are still subscribed afterwards
if not subscribed, the net result is that you end up subscribed
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