We have a class which manages many queues that store data. I want a user to get notified when new data is added to each of these queues. I'd like to use the observer pattern using delegate and events. Normally for a single event and source, we'd do:
public delegate void NewDataAddedDelegate();
public event NewDataAddedDelegate NewDataAdded;
and for the observer:
qManager.NewDataAdded += new qManager.NewDataAddedDelegate(getNewDataFunc);
But in this case, we have, say, 10 queues, each of which can receive data arbitrarily. So we'd like the observer functions to subscribe to an individual queue. We thought we could do:
public delegate void NewDataAddedDelegate();
public event NewDataAddedDelegate [] NewDataAdded; // can't do this
and in the constructor of qManager:
NewDataAdded = new NewDataAddedDelegate[numberOfQueues];
and in the observer:
qManager.NewDataAdded[0] += new qManager.NewDataAddedDelegate(getNewDataFunc0);
qManager.NewDataAdded[1] += new qManager.NewDataAddedDelegate(getNewDataFunc1);
but no go, since the event is expected to be a delegate type, not an array of delegates type.
Any ideas on how to approach this problem?
No, events don't work like that. Options:
Create another type which exposes the event, and have an array or collection of that type:
// Preferably *don't* just expose an array...
public TypeWithEvent[] Queues { get { ... } }
// Subscription:
qManager.Queues[i].NewDataAdded += ...
Alternatively, don't use events, and just have a method:
private NewDataAddededDelegate[] newDataAdded;
public void SubscribeNewDataAddedHandler(int queue,
NewDataAddedDelegate handler)
{
newDataAdded[queue] += handler;
}
// Subscription
qManager.SubscribeNewDataAddedHandler(0, ...);
Personally it sounds to me like each queue should really be its own object though... make the queue manager exposes a collection of queues, each of which can be subscribed to individually. (i.e. take the first approach.) Otherwise your queue manager is really doing too much work.
There are two approaches you might take there; the first is to have:
private NewDataAddedDelegate[] queues; // init not shown
public void Subscribe(int index, NewDataAddedDelegate handler) {
queues[index] += handler;
}
and use
obj.Subscribe(index, ...);
but you may want to think about synchronization etc around the subscription. A second approach is to create a wrapper class that has the event - then you can use the compiler's synchronization, which is good in C# 4.0:
public class SomeQueue {
public event NewDataAddedDelegate NewDataAdded;
}
and then expose those perhaps via an indexer, so you have
obj.Queues[index].NewDataAdded += ...
Personally, I expect the first is easier. It is only the synchronization that might be a nuisance. I do this in some pub-sub code, and IIRC I just lock during the subscribe.
You need to rethink this by actually applying the observer pattern rather that working on the basis of a fuzzy idea of a pattern.
Define your IObserver and ISubject interfaces and try to understand what's the observer and what are the subjects. In your case sounds like the queues are the subjects, not sure what the observers would be in your domain model.
Once you do this, things will be easier to figure out, and it's simply a matter of implementing the methods declared by your interfaces, for example your subjects (queues) will just call notify (and raise an event if you wanna use delegates) when something happens (item added to the queue).
Hope this helps.
Here is the working code in C#.
QueueManger exposes event NewDataAddedEvent which can be subscribed by one or more observers. Queue calls NewDataAdded() method on QueueManager on data change. QueueManager notifies if there are any subscribers with the parameter Queue. I hope this addresses your question.
using System;
using System.Collections.Generic;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
QueueManager queueManager = new QueueManager();
Observer observer = new Observer(queueManager);
Queue queue1 = queueManager.AddQueue();
Queue queue2 = queueManager.AddQueue();
queue1.OnNewDataAdd();
queue2.OnNewDataAdd();
Console.ReadLine();
}
delegate void NewDataAddedDelegate(Queue queue);
class Queue
{
QueueManager queueManager;
public string id;
public Queue(string id, QueueManager queueManager)
{
this.id = id;
this.queueManager = queueManager;
}
public void OnNewDataAdd()
{
this.queueManager.NewDataAdded(this);
}
}
class QueueManager
{
List<Queue> queues = new List<Queue>();
public Queue AddQueue()
{
Queue queue = new Queue((queues.Count + 1).ToString(), this);
this.queues.Add(queue);
return queue;
}
public event NewDataAddedDelegate NewDataAddedEvent;
public void NewDataAdded(Queue queue)
{
if (NewDataAddedEvent != null)
NewDataAddedEvent(queue);
}
}
class Observer
{
public Observer(QueueManager queueManager)
{
queueManager.NewDataAddedEvent += new NewDataAddedDelegate(queue_NewDataAdded);
}
void queue_NewDataAdded(Queue queue)
{
Console.WriteLine("Notification to the observer from queue {0}", queue.id);
}
}
}
}
Perhaps you could use the Event Aggregator pattern.
Not that you would have to code less, but it could create more clean/maintainable code.
Related
I am developing an WPF application and tried to design something event driven using Prism's Event Aggregator.
Currently I am trying to implement something like event queue for Prism events.
To do that I want to subscribe related events and pass them to same method but Event Aggregator wants those methods to have same signature with the event.
Example events:
public class TestEvent1 : PubSubEvent<Class1>
{
}
public class TestEvent2 : PubSubEvent<Class2>
{
}
public class TestEvent3 : PubSubEvent<List<Class3>>
{
}
public class TestEvent3 : PubSubEvent<string>
{
}
Subscriptions:
_eventAggregator.GetEvent<TestEvent1>().Subscribe(OnTestEvent1, true);
_eventAggregator.GetEvent<TestEvent2>().Subscribe(OnTestEvent2, true);
_eventAggregator.GetEvent<TestEvent3>().Subscribe(OnTestEvent3, true);
Example callback method:
private void OnTestEvent1(Class1 object1)
{
// do something
}
Since I only receive data when event published, I tried something like this to use as event payload type, but it doesn't look right:
// Payload
public interface IMessage
{
public object Data { get; set; }
public Type Datatype { get; set; }
public PubSubEvent EventType { get; set; }
}
// Events
public class TestEvent1 : PubSubEvent<IMessage>
{
}
public class TestEvent2 : PubSubEvent<IMessage>
{
}
public class TestEvent3 : PubSubEvent<IMessage>
{
}
// Subscriptions
_eventAggregator.GetEvent<TestEvent1>().Subscribe(EventHandler, true);
_eventAggregator.GetEvent<TestEvent2>().Subscribe(EventHandler, true);
_eventAggregator.GetEvent<TestEvent3>().Subscribe(EventHandler, true);
// Callback
private void EventHandler(IMessage payload)
{
// do something
}
Is this viable and how can I improve or change my "generic" payload?
Extra information:
In my scenario I have multiple UDP servers that periodically receives new data, deserialize it to objects and publish events.
Related "managers" subscribed to those events and get triggered when new data received.
My goal is try to implement an event queue like system in my event receiving classes so it will be easier to deal with multithreading issues.
Here are some diagrams that may help me explain myself better:
My architecture:
My "event queue"
This is more of a code-review question, isn't it?
I would very much prefer strong typing, though, and I wouldn't want to build a queue around the event aggregator, that will always be tedious because you never know when new event types show up. Instead, I'd build my own event aggregator with queueing built in (starting from the existing one).
Also, I'd look into dataflow, for example, because the basic working mode of the event aggregator (fire and forget, one sender, multiple or no receivers) doesn't seem to work well with queueing. If you queue at the sender-side, to you wait for one receiver or all? Do you queue when there are no receivers or do you discard then? If you queue at the receiver-side, why bother at all? The receiver can implement the queue on its own.
When you publish an event with a reference to an object, consider these potential problems:
Any listener will be dependent on the type/assembly of the event parameter.
The referenced object will be held for some time. For how long? You don't know.
The referenced object could have been altered/disposed.
Listeners might handle the referenced object on a different thread.
After dealing with PubSubEvent<T> for several years now, I believe there is only one suitable pattern that successfully handles all cases. Publish your event with a unique identifier, e.g. a Guid.
public class MyItemAddedEvent : PubSubEvent<Guid> {}
Then inject a provider wherever you listen for this event:
public class SomeListener
{
private readonly IMyItemProvider myItemProvider;
[ImportingConstructor]
public SomeListener(IEventAggregator eventAggregator,
IMyItemProvider myItemProvider)
{
this.myItemProvider = myItemProvider;
eventAggregator.GetEvent<MyItemAddedEvent>().Subscribe(OnMyItemAdded, true);
}
private void OnMyItemAdded(Guid id)
{
var myItem = myItemProvider.Get(id);
// Do stuff
}
}
Now it is the responsibility of the provider class to deliver a valid and up-to-date object given a unique id.
In c#,we normally make publisher like below:
public class Publisher
{
public event Action NotifySomethingEvent;
public void RaiseNotifySomethingEvent()
{
NotifySomething?.Invoke();
}
}
while the subscriber has define a method like this:
public void HandlerSomething()
{
Thread.Sleep(2000);
}
This subscriber would cause the publisher thread blocking.
Do there anyway to fix this issue?
By the way,the publisher BeginInvoke method will cause the subscriber execute time confuse,so is not in consideration.
the subscriber execute time confuse means:
class Program
{
static void Main(string[] args)
{
Publisher publisher = new Publisher();
SubScriber subscriber = new SubScriber();
publisher.NotifySomething += subscriber.HandlerSomething;
publisher.RaiseNotifySomething();
publisher.RaiseNotifySomething();
publisher.RaiseNotifySomething();
Console.ReadKey();
}
}
public class Publisher
{
public event Action NotifySomething;
public void RaiseNotifySomething()
{
NotifySomething?.Invoke();
}
}
public class SubScriber
{
int d = 0;
ReaderWriterLock locker = new ReaderWriterLock();
public void HandlerSomething()
{
d += 1;
Action<int> action = new Action<int>((t) =>
{
Thread.Sleep(100);
Console.WriteLine(t);
});
action.BeginInvoke(d, null, null);
}
}
}
the upper code expect result is : 1 2 3
but in fact it result is random,like 1,3,2 1,2,3 or 3,2,1
Apparently you do not want the subscribers to block the publishing thread but do want them to be executed in published order.
You could enqueue your published events and have another thread dequeue these events in order and wait for the subscribers to finish their job.
Building this can get dirty so I recommend you find a Pub-Sub library you feel comfortable with.
I would recommend the MassTransit project. It works async. It has queues. Additionally, you can put the concern of orchestrating the events into a workflow (called a Saga), whicht might come in handy when your project gets more complex.
I am unaware of the complexity of your project. MassTransit supports RabbitMQ but also in-memory as the transport layer. So it scales very well.
It is already done and is called ReactiveExtensions.
It implements IObservable interface which can publish events and you can subscribe to them. It also covers end of events and errors. Take a look.
There even is MVVM framework based on them called ReactiveUI
I have a static class I was using because I didn't like the idea of passing around a gigantic settings file, but then I wished to be able to have instances subscribe to static events on the static class.
I was looking into using the PropertyChangedEventManager's AddListener method, but it needs an instance to add.
is this even possible? i'm on .net 4.0, in case it matters.
You can have a static event and have multiple instances subscribe to it. You'll just have to keep in mind all instances that are wired will get notified of event and their implementation invoked. This also can have issues in memory management, your instances won't go out of scope and get GC'd until they unwire themselves from the event.
Heres an example script to show:
delegate void Pop();
static event Pop PopEvent;
void Main()
{
var t1= new Thing("firstone");
var t2= new Thing("secondOne");
//fire event
PopEvent();
}
public class Thing
{
public Thing(string name)
{
this.name = name;
PopEvent += this.popHandler;
}
private string name="";
public void popHandler()
{
Console.WriteLine("Event handled in {0}",this.name);
}
}
Output:
Event handled in firstone
Event handled in secondOne
Is there a way to specify an order or priority to handle registered event delegates? For example, I have an event that I would like processed immediately before any other events, but I want other objects to be allowed to register listeners to the event as well. How can this be accomplished?
Lets say I want proc1 to always run before proc 2.
class MessageProcessor
{
private DataClient Client;
public MessageProcesser(DataClient dc)
{
Client = dc;
Client.MessageReceived += ProcessMessage;
}
void proc1(MessageEventArgs e)
{
// Process Message
}
}
class DataClient
{
public event MessageReceievedHandler MessageReceived;
}
void main()
{
DataClient dc = new DataClient();
MessageProcessor syncProcessor = new MessageProcessor(dc); // This one is high priority and needs to process all sync immediately when they arrive before any data messages
MessageProcessor dataProcessor= new MessageProcessor(dc); // This one can process the data as it has time when sync messages are not being processed.
// do other stuff
}
The reason for doing this, I have a server that is sending messages over a UDP stream. It will send sync messages before a burst of data. I realize both handlers will fire when a sync message is received, but to decrease latency I would like the syncProcessor objects events processed before the dataProcessor events. This would decrease the latency of the Sync Message being processed.
In addition, someone else on my team may want to register events to process specific messages also. They may have their own object that will register an event (May not be MessageProcessor), even still the Sync message should have as low latency as possible.
EDIT Made the objective more clear with a better example.
When you subscribe to an event multiple times, there is no possible way to be sure of the execution order of your handlers when the event is fired.
According to this answer, the order in the subscription order, but as the post author said, it's an implementation detail and you must not rely on it.
You could of course write your own "event manager" (see dirty example below) that executes your handlers in a known order, but I don't think it would be a good idea. Maybe you should re-design your event to remove your requirement.
public class MyClass
{
// Could be anything...
public delegate void MyEventHandler(object sender, EventArgs e);
public event MyEventHandler TestEvent;
public void Test()
{
if (this.TestEvent != null)
{
this.TestEvent(this, EventArgs.Empty);
}
}
}
public class EventManager
{
private List<EventHandler> Handlers = new List<EventHandler>();
public void AddHandler(EventHandler handler)
{
this.Handlers.Add(handler);
}
public void RemoveHandler(EventHandler handler)
{
this.Handlers.Remove(handler);
}
public void Handler(object sender, EventArgs e)
{
foreach (var z in this.Handlers)
{
z.Invoke(sender, e);
}
}
}
private static void Main(string[] args)
{
MyClass test = new MyClass();
EventManager eventManager = new EventManager();
// Subscribes to the event
test.TestEvent += eventManager.Handler;
// Adds two handlers in a known order
eventManager.AddHandler(Handler1);
eventManager.AddHandler(Handler2);
test.Test();
Console.ReadKey();
}
private static void Handler1(object sender, EventArgs e)
{
Console.WriteLine("1");
}
private static void Handler2(object sender, EventArgs e)
{
Console.WriteLine("2");
}
In this case, you are better off simply calling the second event at the end of the first event, etc.
If this is your own event that you defined, then your best bet might be to extend it to have a BeforeMessageReceived, MessageReceived and AfterMessageReceived events. (okay, so maybe MessageProcessed would be a better root, since you can know before a message is received).
This will give you more control over exactly where different event handlers occur.
You see the same before, event, after patten all over the place.
Im going to go out on a limb and say no. AFAIK events are dispatched ASYNCHRONOUSLY by nature. So that will be dispatched in the order they are bound. however the results may return in a different order. The only way would be to dispatch your 2nd event inside the callback for the first event. This is not language specific, just more on the architecture of events.
In your example since the calls are void y not run proc2 at the end of proc1?
I've got the following class:
public class Terminal : IDisposable
{
readonly List<IListener> _listeners;
public Terminal(IEnumerable<IListener> listeners)
{
_listeners = new List<IListener>(listeners);
}
public void Subscribe(ref Action<string> source)
{
source += Broadcast;
//Store the reference somehow?
}
void Broadcast(string message)
{
foreach (var listener in _listeners) listener.Listen(message);
}
public void Dispose()
{
//Unsubscribe from all the stored sources?
}
}
I've searched for a while and it appears that an argument passed with the ref keyword can't be stored. Trying to add the source argument to a list or to assign it to a field variable doesn't allow it to keep a reference to the actual delegate's original reference; so my questions are:
Is there a way to unsubscribe from all the sources without passing their references again?
If not, how can the class be changed in order to support it, but still maintain the subscription by passing a delegate through a method?
Is it possible to achieve it without using Reflection?
Is it possible to achieve it without wrapping the delegate/event in a class and then passing the class as a parameter for the subscription?
Thank you.
EDIT: It appears that without using a Wrapper or Reflection, there's no solution to the given problem. My intention was to make the class as much portable as possible, without having to wrap delegates in helper classes. Thanks everyone for the contributions.
Edit: Ok, that was a bad idea, so back to the basics:
I recommend creating a wrapper class over an Action:
class ActionWrapper
{
public Action<string> Action;
}
And restructuring your initial class to work with wrappers:
private ActionWrapper localSource;
public void Subscribe(ActionWrapper source)
{
source.Action += Broadcast;
localSource = source;
}
public void Dispose()
{
localSource.Action -= Broadcast;
}
Now you should get the desired results.
public class Terminal : IDisposable
{
List<IListener> _listeners;
List<Action<string>> _sources;
public Terminal(IEnumerable<IListener> listeners)
{
_listeners = new List<IListener>(listeners);
_sources = new List<Action<string>>();
}
public void Subscribe(ref Action<string> source)
{
_sources.Add( source );
source += Broadcast;
}
void Broadcast(string message)
{
foreach (var listener in _listeners) listener.Listen(message);
}
public void Dispose()
{
foreach ( var s in _sources ) s -= Broadcast;
}
}
I would suggest that the subscription method should return an implementation of a SubscriptionHelper class, which implements IDisposable. A simple implementation would be for SubscriptionHelper to hold a reference to the subscription list and a copy of the subscription delegate; the subscription list itself would be a List<SubscriptionHelper>, and the Dispose method for SubscriptionHelper would remove itself from the list. Note that if the same delegate gets subscribed multiple times, each subscription will return a different SubscriptionHelper; calling Dispose on a SubscriptionHelper will cancel the subscription for which it had been returned.
Such an approach would be much cleaner than the Delegate.Combine/Delegate.Remove method used by the normal .net pattern, whose semantics can get very strange if an attempt is made to subscribe and unsubscribe multi-target delegates.
EDIT:
Yep, my bad - delegates are immutable types, so adding a method to an invocation list will actually create a new delegate instance.
Which leads to an answer no to your question. To unsubscribe the delegate you need to remove your Broadcast method from the delegate's invocation list. This means creating a new delegate and assigning it to the original field or variable. But you cannot access the original once you're out of Subscribe method. Plus there can be other copies of that original field/variable that have your method on the invocation list. And there is no way for you to know about all of them and change there values.
I'd suggest to declare an interface with the event for your purpose. This will be quite flexible approach.
public interface IMessageSource
{
event Action<string> OnMessage;
}
public class MessageSource : IMessageSource
{
public event Action<string> OnMessage;
public void Send(string m)
{
if (OnMessage!= null) OnMessage(m);
}
}
public class Terminal : IDisposable
{
private IList<IMessageSource> sources = new List<IMessageSource>();
public void Subscribe(IMessageSource source)
{
source.OnMessage += Broadcast;
sources.Add(source);
}
void Broadcast(string message)
{
Console.WriteLine(message);
}
public void Dispose()
{
foreach (var s in sources) s.OnMessage -= Broadcast;
}
}
Original answer
Is there a particular reason why you pass source delegate as ref? You need this if you, for example, want to return a different delegate from the method.
Otherwise, the delegate is reference type, so you can subscribe to it without passing it as ref...
It's reasonably simple, but there are a few pitfalls. If you store a reference to the source objects, as most of the examples so far have proposed, the object won't be garbage collected. The best way to avoid this is to use an WeakReference, that will allow the GC to work properly.
So, all you have to do is this:
1) Add a list of sources to the class:
private readonly List<WeakReference> _sources = new List<WeakReference>();
2) Add the source to the list:
public void Subscribe(ref Action<string> source)
{
source += Broadcast;
//Store the reference
_sources.Add(new WeakReference(source));
}
3) And then just implement dispose:
public void Dispose()
{
foreach (var r in _sources)
{
var source = (Action<string>) r.Target;
if (source != null)
{
source -= Broadcast;
source = null;
}
}
_sources.Clear();
}
That said, there's also the question of why the Action must be passed as a ref. In the current code, there's no reason for that. Anyway, it doesn't affect the problem or the solution.
Perhaps, instead of trying to store a reference to the delegate, have what calls Subscribe use its reference to the object with the delegate to create actions for the subscription and unsubscription . Its an additional parameter, but its still straightforward.
public void Subscribe(Action<Action<string>> addHandler,Action<Action<string>> removeHandler)
{
//Prevent error for possibly being null in closure
Action<string> onEvent = delegate { };
//Broadcast when the event occurs, unlisten after (you could store onEvent and remove handler yourself)
onEvent = (s) => { Broadcast(s); removeHandler(onEvent); };
addHandler(onEvent);
}
And an example subscribing.
public event Action<string> CallOccured;
public void Program()
{
Subscribe(a => CallOccured += a, a => CallOccured -= a);
CallOccured("Hello");
}