Store a list of EventHandlers to unsubscribe from - c#

I have a class with a method, Register that subscribes to a number of events on classes that it contains, using the standard aClass.SomeEvent += the_handler. This class also has an Unregister method that unsubscribes from these events using -=. This works just fine but we're finding that if we add a new event to subscribe to that it's very easy to forget to include the unsubscription in Unregister. This manual method of maintaining event subscriptions is proving to be fragile.
Is there a way to maintain a list of subscriptions that can be iterated over and unsubscribed from dynamically? (And potentially iterate over and re-subscribe when calling Register after Unregister).
Some details: The class has a reference to 3 other classes (currently, but not definitively limited to 3), the various events on these classes are all of type EventHandler or EventHandler<T>.

how about getting invocation list from the EventHandler.GetInvocationList() and then ierate through and manually remove/unregister them ? note, you only have access to the GetInvationList() method from the class that has that EventHandler, so you might need to expose a method UnregisterAll() to make sure it removes all the delagates in the event invocation list
you can also make sure your class inherits IDisposable and with using(){ } it will call Dispose which will clean up all subscribers

After a thorough look through SO I found this answer:
C# Dynamic Event Subscription
That does what I want (almost). I don't like having to name events using strings as and such I won't be pursuing this design any further. Even though it's not the design I want, the answer shows a very useful method to achieve the desired behaviour and as such I'm marking this as accepted.

Related

Can I depend on event handlers being invoked in order of registration?

In the current version of the .NET framework, and under normal circumstances (i.e. without intentionally modifying the invocation list), are handlers for an event always invoked in the order in which they are registered? This would be consistent with the documented behavior of multicast delegates, with which events are implemented.
The accepted answer to this question says that invoking handlers in the order of their registration is an implementation detail that may change in some future version of the framework. I believe such a change by Microsoft is unlikely, therefore I am confining my question to the current version of the .NET framework. A comment on that same answer says that it is possible to register handlers such that they are not invoked in their registration order. If this is true then please demonstrate code that results in this out-of-order execution. Please do not include code which intentionally modifies the invocation list. What I am after here is whether or not I can depend on event handler invocation occurring in same order as registration in all current versions of the .NET framework.
You cannot be sure that an event will always be executed in a particular order. The definition of the event can always do whatever it wants, and the implementation of that event is not a part of the public API.
By default, events will use a single multicast delegate as the backing store for an event, but it is straightforward enough to use your own implementation instead. There is no way to tell (beyond looking at the source code) whether or not an event has a custom implementation or not.
One way of implementing an event to not have the described order would be:
public class Foo
{
private Stack<Action> stack = new Stack<Action>();
public event Action MyEvent
{
add
{
stack.Push(value);
}
remove { throw new NotImplementedException(); }
}
internal void OnMyEvent()
{
foreach (var action in stack)
action();
}
}
While most of the events in framework classes won't use a definition like this; most will use a multicast delegate, the only way to know is to look at the source code; you can't tell from, for example, looking at the documentation, whether an event is implemented like this or like:
public class Foo2
{
public event Action MyEvent;
}
That depends on how the event is implemented.
Ordinary (field-like) events store all of their handlers in a single multicast delegate.
Multicast delegates invoke their handlers in insertion order.
Other events are free to store their handlers in some other order. However, most non-standard implementations still use multicast delegates under the covers, stored in various ways (eg, EventHandlerList)

Disconnected Event registration and subscription

The publisher exposes an event to which multiple subscribers can hook up to
on subscriber side -> publisher.OnSomeEvent += subscriber.CallMe()
Later the subscriber subscribes based on some dynamic arguments
publisher.Subscribe(arguments)
publisher.Unsubscribe(arguments)
Depending on what arguments are passed by the subscriber, I want publisher to update subscribers for the content they have subscribed.
Internally i can maintain a map of subscriber to arguments but my problem is that as event registration and subscription are disconnected i can't find a good way to pass the callee handle (so i can maintain a map subscriber->arguments) when calling Subscribe/Unsubscribe call.
To keep my API simple i don't want callee to pass "this", also as StackFrame and diagnostics API does not work in release mode because of inlining issue, i can't think of a better design.
Appreciate your help if you can suggest a better way to achieve this?
This isn't the most elegant solution, but you could have the publisher deal with the subscriber through an interface which would decouple the publisher from needing to know about any specific subscriber implementation.
For example
interface ISubscriber
{
object Arguments{get;}
}
Which would make the client API signature:
void Subscribe(ISubscriber subscriber)
Of course you may want to implement the interface on a seperate type if you don't want your subscriber types having an Arguments property.
If you want to filter the publications, I say ditch the event and instead use something like
publisher.Subscribe(arguments, subscriber.CallMe)
To unsubscribe you must have some dort of identifier, could be a GUID, string, int, this (not sure why you want to avoid it)...

How to manipulate at runtime the invocation list of a Delegate?

I want to know how do I go about removing individual delegates from the invocation list of the parent delegate.
<DelegateName>.RemoveAll();
Now I can just remove all and that will work just to get the idea in motion and see if works which it should but then any delegates removed will need adding again at RunTime!!!
so: ...
foreach(Delegate d in <DelegateName>.getInvocationList)
{ // do something with 'D'?? }
Now that I have access to 'D' I can drop it into a .Remove() but it requies two arguments??? Could I get some help with this please?
Lastly, once the delegate has been removed, what is the best way to re-add it again?
So i'm assuming Reflection might play a part in this but over to you guys.
UPDATE:
Essentially there is a global delegate that has many events living in different winforms classes that are instances of it. All of these events have a handler that handles the event when it is fired. The delegate all the way at the top governs all handlers that match its signature are fired. I want to mess about with this delegate at the top, I want to remove all handlers and then re-add them at run time. So the delegate at the top is a multicast delegate and its invocation list is a list of individual delegates that in turn point to one of the four handlers that I have added. I hope that makes sense, thats a general idea of whats I am doing.
You can't - delegates are immutable. You can create a new delegate which is equivalent to the old one without certain actions, but you can't modify the existing one in-place.
Invocation list is internal piece of delegate, you can't modify it normally. You may be able to do it by very dirty reflection, but i don't think that it is valid idea for production code. But there is another way to solve it validly. You can define event without automatic underlaying delegate and control the invocation list yourself. For that you need to define event with explicit add and remove keywords, see here. You will have to reimplement some stuff for that but it will give you full control.

Why should derived classes handle an event without attaching a delegate?

Q1:
“The ListControl.OnSelectedIndexChanged method also allows derived classes to handle the event without attaching a delegate. This is the preferred technique for handling the event in a derived class.”
A) If I understand the above quote, then if we derive a class from ListControl, we should instead of subscribing to SelectedIndexChanged event, treat OnSelectedIndexChanged() method as an event handler and thus put any event processing logic inside it:
protected override void OnSelectedIndexChanged(
EventArgs e
{
//event handling logic
}
Why would that be better than subscribing to an event(inside .aspx) via OnSelectedIndexChanged = ”name_of_event_handler”?
B)
Anyways, in ascx file we use OnSelectedIndexChanged attribute to attach event handler to an event. Name of this attribute is the same as the name of OnSelectedIndexChanged() method. Why is that? Why isn't instead the name of this attribute SelectedIndexChanged:
<asp:ListControl SelectedIndexChanged = ”name_of_event_handler”
Afterall, attribute refers to an event and not to a method ( OnSelectedIndexChanged() ) that calls this event!
thanx
EDIT:
Hello,
HOWEVER, be sure that you call base.On[EventName] or the event won't fire!
Assuming you don’t want anyone else to be able to respond to this event, then would it be perfectly OK not to call base.On[EventName], since I would think not calling it won’t really do any harm besides not firing an event ( and thus event handlers won't be called )?
I realize some events need to be fired in order for Framework to do its job, but what about not calling base.On[SelectedIndexChanged]?
It is "better" in that:
it is cheaper to use virtual (inheritance) where possible - it removes the need for a few extra objects (delegate instances, etc)
it allows the overriding code to know where it comes in the sequence - i.e. if multiple callers are listening, does it fire first? second? in the middle?
The first point is arguably more important for efficiency, especially in things like controls that have sparse event handlers (i.e. things like EventHandlerList instead of a field-like-event).
I don't really understand the second question, but at a guess: convention.
In general, I prefer to override the On[EventName] functions so that I can control if my logic happens before or after the logic in any subscribers.
HOWEVER, be sure that you call base.On[EventName] or the event won't fire!

Alternate of C# Events in Java

I am .Net developer. i want to know that is there any event handling mechanism in Java for Events Handling like C#.
what i want to do is i want to raise/fire an event form my class upon some condition. and consumer of this class should register that event and write event handling method.
this can be done easily in C#. i have to implement this thing in Java.
after googling out i found some links but all those are talking about GUI events in AWT and swing.
can any one help me out.
Although most of the examples will be to do with GUI events, the principles are basically the same. You basically want an interface or abstract class to represent a handler for the event, e.g.
public interface EventHandler
{
// Change signature as appropriate of course
void handleEvent(Object sender, EventArgs e);
}
then the publisher of the event would have:
public void addEventHandler(EventHandler handler)
public void removeEventHandler(EventHandler handler)
It would either keep a list of event handlers itself, or possibly have them encapsulated in a reusable type. Then when the event occurs, you just call handleEvent in each handler in turn.
You can think of delegate types in C# as being very similar to single-method interfaces in Java, and events are really just an add/remove pair of methods.
I love C# Events,
They are simple to use and convenient. i missed them in java so wrote a small utility class that mimics the very basics of C# Event.
using java 8 (for lambdas)
no += operator, instead call .addListener((x) -> ...)
to trigger an event, call .broadcast(<EventArgs insance>)
Online Demo - https://repl.it/DvEo/2
Event.java
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
public class Event {
private Set<Consumer<EventArgs>> listeners = new HashSet();
public void addListener(Consumer<EventArgs> listener) {
listeners.add(listener);
}
public void broadcast(EventArgs args) {
listeners.forEach(x -> x.accept(args));
}
}
You may want com.google.common.collect.Sets.newConcurrentHashSet() for thread safety
EventArgs.java
public class EventArgs {
}
Java has support through various event handling implementations - the simple Observer/Observable in java.util, PropertyChangeEvents in java.beans, and GUI events which inherit from AWTEvent.
An Observable object has a list of observers which implement the Observer interface, and mechanisms for adding and removing observers. If o.notifyObservers(x) is called on the observable, update(o,x) will be called on each observer. This mechanism is somewhat old fashioned and rarely used in new code - it dates from Java 1.0 before EventObject was added in Java 1.1 and better event handling added for AWT and beans.
Beans and GUI events propagate an object which extends java.util.EventObject to listeners which implement a sub-interface of EventListener. Usually if you're using an existing API you will only care about the events and listeners for that API, but if you're defining an API the events and listeners should follow that convention.
It's also the convention in Java APIs to call the handlers for events "listeners" rather than handlers, and all listener interface names end with Listener. The names of the methods don't start with 'on' but should be past tense -mouseMoved or handshakeCompleted rather than onMouseMove or handleMouseMove.
The PropertyChangeSupport class provides an implementation of the mechanism for adding and removing listeners from a bean, and is also used for properties of Swing widgets.
If you write your own listener handling, it's conventional to allow listeners to remove themselves by calling source.removeXXXListener(this) from within their event handling method. Just iterating over a simple collection of listeners and calling their handling methods would give a ConcurrentModificationException with in these cases - you need to copy the collection of listeners or use a concurrently modifiable collection.
Check out this tutorial. It goes through some of the Swing event handling stuff that you have come across in your searches, but the concepts are pretty general. In simple terms, event handlers maintain a collection of listeners (implementing an interface) and iterate over them when they fire an event, calling the method in the interface.

Categories

Resources