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)...
Related
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)
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.
Whenever i feel hungry i will publish i am hungry.This will be notified to the service providers say (MealsService,FruitService,JuiceService ).(These service providers know what to serve).
But the serving priority is the concern. Priority here means my first choice is MealsService when there are enough meal is available my need is end with MealsService.To verify the enough meal is availabe the MealsService raises the event "updateMeTheStockStatus" to the "MealsServiceStockUpdateListener" .
The "MealsServiceStockUpdateListener" will only reply back to "MealsService" . No other Service providers ( FruitService,JuiceService ) will be notified by the "MealsServiceStockUpdateListener" .If there is no sufficient stock then only the MealsService passes notification to the JuiceService (as it is the second priority).As usual it checks the stock.If stock is not sufficient it passes message to FruitService,so the flow continues like this.
How can i technically implement this?
Any implemention like priority based delagates and delegate chaining make sense ?
(Somebody! Please reframe it for good readability ).
Update : In this model there is no direct communication between "StackUpdateListener" and "me".Only The "Service Providers" will communicate me.
Like other answerers, I'm not entirely convinced that an event is the way forward, but let's go along with it for the moment.
It seems to me that the business with the MealsServiceStockUpdateListener is a red herring really - you're just trying to execute some event handlers but not others. This sort of thing crops up elsewhere when you have a "BeforeXXX" event which allows cancellation, or perhaps some sort of exception handling event.
Basically you need to get at each of your handlers separately. There are two different ways of doing that - either you can use a normal multicast delegate and call GetInvocationList() or you can change your event declaration to explicitly keep a list of handlers:
private List<EventHandler> handlers = new List<EventHandler>();
public event EventHandler MealRequired
{
add { handlers.Add(value); }
remove
{
int index = handlers.LastIndexOf(value);
if (index != -1)
{
handlers.RemoveAt(index);
}
}
}
These two approaches are not quite equivalent - if you subscribe with a delegate instance which is already a compound delegate, GetInvocationList will flatten it but the List approach won't. I'd probably go with GetInvocationList myself.
Now, the second issue is how to detect when the meal has provided. Again, there are two approaches. The first is to use the normal event handler pattern, making the EventArgs subclass in question mutable. This is the approach that HandledEventArgs takes. The second is to break the normal event pattern, and use a delegate that returns a value which can be used to indicate success or failure (and possibly other information). This is the approach that ResolveEventHandler takes. Either way, you execute the delegates in turn until one of them satistfies your requirements. Here's a short example (not using events per se, but using a compound delegate):
using System;
public class Test
{
static void Main(string[] args)
{
Func<bool> x = FirstProvider;
x += SecondProvider;
x += ThirdProvider;
Execute(x);
}
static void Execute(Func<bool> providers)
{
foreach (Func<bool> provider in providers.GetInvocationList())
{
if (provider())
{
Console.WriteLine("Done!");
return;
}
}
Console.WriteLine("No provider succeeded");
}
static bool FirstProvider()
{
Console.WriteLine("First provider returning false");
return false;
}
static bool SecondProvider()
{
Console.WriteLine("Second provider returning true");
return true;
}
static bool ThirdProvider()
{
Console.WriteLine("Third provider returning false");
return false;
}
}
Rather than publish a message "I'm hungry" to the providers, publish "I need to know current stock available". Then listen until you have enough information to make a request to the correct food service for what you need. This way the logic of what-makes-me-full is not spread amongst the food services... It seems cleaner to me.
Message passing isn't baked into .NET directly, you need to implement your own message forwarding by hand. Fortunately, the "chain of responsiblity design pattern" is designed specifically for the problem you're trying to solve, namely forwarding a message down a chain until someone can handle it.
Useful resources:
Chain of Responsibility on Wikipedia
C# implementation on DoFactory.com
I'm not sure if you really need a priority event. Anyways, let's suppose we want to code that just for fun.
The .NET Framework has no support for such a peculiar construct. Let me show one possible approach to implement it.
The first step would be to create custom store for event delegates (like described here);
Internally, the custom event store could work like a priority queue;
The specific EventArgs used would be HandledEventArgs (or a subclass of it). This would allow the event provider to stop calling handlers after one of them sets the event as Handled;
The next step is the hardest. How to say to tell the event provider what is the priority of the event handler that is being added?
Let me clarify the problem. Usually, the adding of a handler is like this:
eater.GotHungry += mealsService.Someone_GotHungry;
eater.GotHungry += juiceService.Someone_GotHungry;
eater.GotHungry += fruitService.Someone_GotHungry;
The += operator will only receive an delegate. It's not possible to pass a second priority parameter. There might be several possible solutions for this problem. One would be to define the priority in a custom attribute set at the event handler method. A scond approach is discussed in the question.
Compared to the chain of responsibility implementation at dofactory.com, this approach has some advantages. First, the handlers (your food services) do not need to know each other. Also, handlers can be added and remove at any time dynamically. Of course, you could implement a variation of a chain of responsibility that has this advantages too.
I don't think delegates are the proper solution to your problem. Delegates are a low-level service provided by C# for relatively tightly coupled events between components. If I understand your question properly (It is worded a little oddly, so I am not sure I clearly understand your problem), then I think what you need is a mediated consumer/provider.
Rather than having your consumers directly consume the meal, juice, and fruit providers, have them request a food item from a central mediator. The mediator would then be responsible for determining what is available and what should be provided to the consumer. The mediator would be a subscriber to events published by all three services. Whenever stock is added/updated in the Meal, Juice, or Fruit services, they would publish their current stock to all subscribers. The mediator, being a subscriber, would track current stock reductions on its own, and be able to determine for itself whether to send a meal, juice, or fruit to a food consumer when a get food request is made.
For example:
|---------- (GetFoodResponse) ----------------
V |
FoodConsumer ---- (GetFoodRequest) ------> FoodProvider <-----> [ Local Stock Data ]
^
|
|
MealService ---- (PublishStockMessage) ----------|
^
JuiceService --- (PublishStockMessage) ----------|
^
FruitService --- (PublishStockMessage) ----------|
The benefits of such a solution are that you reduce coupling, properly segregate responsibility, and solve your problem. For one, your consumers only need to consume a single service...the FoodProvider. The FoodProvider subscribes to publications from the other three services, and is responsible for determining what food to provide to a consumer. The three food services are not responsible for anything related to the hunger of your food consumers, they are only responsible for providing food and tracking the stock of the food they provide. You also gain the ability to distribute the various components. Your consumers, the food provider, and each of the three food services can all be hosted on different physical machines if required.
However, to achieve the above benefits, your solution becomes more complex. You have more parts, and they need to be connected to each other properly. You have to publish and subscribe to messages, which requires some kind of supporting infrastructure (WCF, MSMQ, some third party ESB, custom solution, etc.) You also have duplication of data, since the food provider tracks stock on its own in addition to each of the food services, which could lead to discontinuity in available stock. This can be mitigated if you manage stock updated properly, but that would also increase complexity.
If you can handle the additional complexity, ultimately, a solution like this would more flexible and adaptable than a more tightly connected solution that uses components and C# events in a local-deployment-only scenario (as in your original example.)
I am having a bit of trouble understanding your analogy here, which sounds like you're obscuring the actual intent of the software, but I think I have done something like what you are describing.
In my case the software was telemarketing software and each of the telemarketers had a calling queue. When that queue raises the event signifying that it is nearing empty, the program will grab a list of available people to call, and then pass them through a chain of responsibility which pushes the available call into the telemarketer's queue like so:
Each element in the chain acts as a priority filter: the first link in the chain will grab all of the people who have never been called before, and if it finishes (ie. went through all of the people who have never been called) without filling up the queue, it will pass the remaining list of people to call to the next link in the chain - which will apply another filter/search. This continues until the last link in the chain which just fires off an e-mail to an administrator indicating that there are no available people to be called and a human needs to intervene quickly before the telemarketers have no work to do.
I'm working on an application that loads untrusted assemblies via an interface. Each of those assemblies should be able to add one or more GameAction objects to a thread-safe queue used by the server.
The first iteration of design was to just pass the queue--something like this:
public interface IGameClient
{
void HandleStateChange(IGameState gameState,
ref Queue<IGameAction> actionQueue);
}
But, the problem with this is that it gives an untrusted assembly access to a shared queue, allowing it to manipulate other members of the queue and discover information about other queue actions.
The second pass was:
public interface IGameClient
{
void HandleStateChange(IGameState gameState);
GameActionDelegate event HasNewEvent; // passes IGameAction as a parameter
}
The problem with this is that it doesn't necessarily allow for the ordering or grouping of actions.
What I'm really hoping for is to be able to pass a reference to an object that encapsulates the thread-safe queue, but only exposes Enqueue(). But, I'm afraid that an untrusted assembly could manipulate a private Queue object using reflection.
So, what's the best way to handle this?
Thoughts in no particular order:
1) Events do guarantee ordering (or at least, your implementation could guarantee whatever ordering you want, and the simplest implementations will preserve ordering).
2) I don't see why you'd want to pass the queue by reference in the first example of the interface. It may be worth checking that you understand parameter passing and "ref".
3) If you come up with an interface which only exposes Enqueue then the implementation presumably won't be a Queue<T>. It might contain a Queue<T>, but if you really don't trust assemblies not to mess around with your private members, you should load them in such a way that you don't grant them the relevant reflection permissions.
Another alternative might be to pass in an Action<IGameAction> which the client can call when it wants to add an item to the queue. The delegate would be created from whatever Enqueue method you've got.
Don't expose the queue at all--simply expose a method on a facade that allows the GameClient to submit an entry that the GameServer will place on the internal queue.
You could make the HandleStateChange method return an IEnumerable<IGameAction>, IList<IGameAction> or IGameAction[]:
public interface IGameClient
{
IGameAction[] HandleStateChange(IGameState gameState);
}
Then use that return value to add actions to the queue.
Pass a newly-created instance of queue, and when the HandleStateChange returns, merge the stuff from your dummy queue into the real queue.
It's known that you should declare events that take as parameters (object sender, EventArgs args). Why?
This allows the consuming developer the ability to write a single event handler for multiple events, regardless of sender or event.
Edit: Why would you need a different pattern? You can inherit EventArgs to provide any amount of data, and changing the pattern is only going to serve to confuse and frustrate any developer that is forced to consume this new pattern.
Actually this is debatable whether or not this is the best practice way to do events. There is the school of thought that as events are intended to decouple two segments of code, the fact that the event handler gets the sender, and has to know what type to cast the sender into in order to do anything with it is an anti-pattern.
Because it's a good pattern for any callback mechanism, regardless of language. You want to know who sent the event (the sender) and data that is pertinent to the event (EventArgs).
Using a single parameter, EventArgs, for the data passed by an event allows you to add data to your event in future versions of your software without breaking existing consumers. You simply add new members to an existing EventArgs-derived class, or create a derived class with the new members.
Otherwise consistency and the principle of least surprise justify using EventArgs for passing data.
As for sender, in some (but not all) cases it's useful to know what type sent the event. Using a type other than object for the sender argument is too restrictive: it would mean that other senders couldn't reuse the same event signature.
It is a good pattern to use, that way what ever implements the event can find what was sending it.
Also overriding the EventArgs and passing data through them is the best method. The EventArgs are a base class. If you look at various controls that call events, they have overridden EventArgs which gives you more information about the event.
Even if you don't need the arguments to do the event, if you do not include them with the first run of the framework and want to add them later, you break all previous implementations, and have to re-write them. Plus if you a creating a framework and going to distribute that it becomes worse because everybody that uses your framework will need to refactor.
Chris Anderson says in the Framework Design Guidelines book:
[T]his is just about a pattern. By having event arguments packaged in a class you get better versioning semantics. By having a common pattern (sender, e) it is easily learned as the signature for all events.
There are situations mostly involving interop that would require deviation from this pattern.
It seemed that this was Microsoft's way to evolve the event model over time. It also seems that they are also allowing another way to do it with the "new" Action delegate and it's variations.
Sometimes you would like to force all of your event consumers to use a particular event parameter, for example, a security event which passes a boolean parameter, true for good, false for bad.
In this case you want your consumer to be painfully aware of the new parameter, i.e. you want your consumers to be coupled with that parameter. Take note, your consumers are still decoupled from your event firing class, but not from your event.
I suspect that this scenario applies to a large number of cases and in those cases the value of EventArgs is greatly reduced.
"Object sender" allows to reuse one method for multiple objects when the handler method is supposed to do something with the object that raised the event, for example 3 textbox can have one single handler that will reset the text of the firing textbox.
EventArgs's main advantage is that it allows to refactor event information without the need to change signatures of all handlers in all projects that are subscribed to this kind of event.
I can't think of a smarter way to deal with events.
The EventArgs class alone is useless since it must be derived to instantiate with any content. This would indicate a subclass should be used, and many already exist in .NET. Sadly, I can't find any good generic ones.
Let's say you want to delegate logging to a generic event... WITHOUT WRITING YOUR OWN EventArgs SUBCLASS. It may seem a pointless exercise, but I like using existing features. You can pass your string through the Object argument, but that goes against it's intended use. Try to find a good reference of EventArgs subclasses on Google, and you'll come up dry. (At least I did.)
ReSharper helps a bit, since when you type "EventArgs" you'll see a list of all classes (within your using/imports scope) that CONTAIN the string "EventArgs". Perusing the list you'll see many classes with no string members. When you get to ControlEventArgs, you see that the Text property might be used, but with all of the overhead of a windows control. ConvertEventArgs might be useful, since you pass the type along with the data, but this still requires tight coupling that's neither well-documented nor inherently type-safe. DataReceivedEventArgs has no implementation. EntryWrittenEventArgs requires an EventLogEntry with a byte array or StreamingContext for data. ErrorEventArgs is closer, with an Exception message, if you don't mind calling all of your log events Exception ErrorEvents internally. FileSystemEventArgs is probably the closest yet, with two strings and a required WatcherChangeTypes enum argument that CAN be set to 0, if you know what you're doing. LabelEditEventArgs uses an int and a string, if you don't mind requiring the Windows.Forms namespace. RenamedEventArgs is similar to FileSystemEventArgs with an extra string. Finally, ResolveEventArgs in System.Runtime.InteropServices passes a single string. There are other libraries, but I stuck to some of the most common ones. So, depending on the implementation I can use ErrorEventArgs, FileSystemEventArgs or ResolveEventArgs for logging.