Consider this code:
class GameEventsManager
{
public void StartGameEvent(GameEvent TheGameEvent)
{
SubscribeToGameEvent(TheGameEvent);
TheGameEvent.Begin();
UnsubscribeToGameEvent(TheGameEvent);
}
private void SubscribeToGameEvent(GameEvent TheGameEvent)
{
TheGameEvent.OnPlaySound += OnPlaySound;
TheGameEvent.OnShowWrittenItem += OnShowWrittenItem;
...
}
private void UnsubscribeToGameEvent(GameEvent TheGameEvent)
{
TheGameEvent.OnPlaySound -= OnPlaySound;
TheGameEvent.OnShowWrittenItem -= OnShowWrittenItem;
...
}
}
A GameEvent is a class that basically does this: when Begin() gets called, it raises events that get passed to the GameEventManager, so that it may "make" the appropriate changes to the game environment (this is by further propagating the events to the objects that are responsible for executing each particular instruction, like in the Observer pattern).
Now take into consideration that all of my InventoryItems (can trigger events, such as OnConsume, OnUse) are static fields in their particular classes. Although this may seem a bit rough around the edges, I feel that being able to do:
AddItem(WrittenItems.NoteFromKing) //NoteFromKing is a static field in WrittenItems
makes things a lot simpler, and it's a welcome sight considering I'm working on a quite complex game.
This, however, makes it very hard for me to list ALL of the game's items somewhere, in case this would be needed. Which brings us to my question:
A LevelManager, that manages things such as when the player interacts with a particular item in the level, tells the GameEventsManager to run a particular GameEvent, if required. The GameEventsManager then subscribes to the GameEvent, starts it, and then unsubscribes. Should I expect to see noticeable performance issues while following this subscribe/run/unsubscribe pattern? In the end, the manager might subscribe/unsubscribe to about 20 events inside GameEvent.
In case the subscribe/unsubscribe mechanism is slow, I could make a single subscribe process that runs at game initialization, but that would force me to build an extra structure, to list all of the items.
So, in short, I'd like to know if I should be expecting considerable slowdowns from this kind of implementation. Or more exactly, if subscribing to about 20 events, and then unsubscribing from them is considerably slow.
Language is C#, using .NET 2.0 subset under Unity 4.
This, however, makes it very hard for me to list ALL of the game's items somewhere
Why so? You could create an ItemManager (which is a singleton):
public class ItemManager
{
private static volatile ItemManager _instance;
private static object syncRoot = new Object();
private ObservableCollection<ItemBase> _registeredItems = new ObservableCollection<ItemBase>();
private ItemManager()
{
}
public ItemManager Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new ItemManager();
}
}
return instance;
}
}
public void RegisterItem(ItemBase item)
{
_registeredItems.Add(item);
// Do some stuff here, subscribe events, etc.
}
public void UnregisterItem(item)
{
// Do some stuff here, unregister events, etc.
_registeredItems.Remove(item)
}
}
Afterwards you make all item classes derive from a class called "ItemBase". And in ItemBases Constructor you call this:
ItemManager.Instance.RegisterItem(this);
So you don't have to add every single item manually. For more information about the singleton pattern, take a look here: http://msdn.microsoft.com/en-us/library/ff650316.aspx.
A little benefit of this is also, that you can implement a general communication between the GameManager and the ItemManager.
Related
Should the event subscriber always register the event handler, or is it ok for another class to do it?
Example:
class EventPublisher {
public event EventHandler Event;
}
class EventSubscriber {
public void Handler(object sender, EventArgs e) { }
}
class Glue {
private EventPublisher _publisher = new EventPublisher();
private EventSubscriber _subscriber = new EventSubscriber();
public Glue() {
_publisher.Event += _subscriber.Handler;
}
}
Should the event subscriber always register the event handler, or is
it ok for another class to do it?
There is nothing inherently wrong with this design per se, though it really depends on your architecture and how scaleable and decoupled you want it.
Just a note, there is no context with the generic hypothetical you have put forward with Glue so its hard to tell your exact requirements.
...
These days, i rarely write traditional events and tend to use a more modern approach of Pub/Sub Producer/Consumer Decoupled Messages or an Event Aggregator (depending on the frameworks you are using). Consumers can subscriber at will, and producers can publish at will without any prior knowledge of each other. Martin Follower goes into this pattern in more detail on his site.
More-so, the advantages with Decoupled Messages (and kin), is consumers can subscribe to a conversation without having any previous knowledge of who the producers are, which gives you better decoupling which in turn creates a more maintainable and scalable system. If the system becomes large enough, pushing classes to Microservices can be a lot less painful.
On saying that, if this is only a very simple implementation (and tightly coupled implementation) there is nothing wrong with standard vanilla ice-cream flavored .NET events and having your subscriber register the event handler, though once again you have to break this down into the most logical concern for your design.
I.e should a SoundManager inherently know about a dog and its bark. Or should your dog class register to the sound manager. Your design intuition should lead the way
Anyway, good luck.
Programmatic, it is not wrong and will work smooth for you.
In fact you need to do this in the case where in EventSubscriber of which method
(Handler)should be called on Event , doesn't have object of EventPublisher class.
How to subscribe events is subjective matter, it depends on your over all flow and comfort.
But According to me, subscribing event in side of subscriber class make code more readable and easy to understand
you see to subscribe an event of any class, subscriber class must have an object of that class, but here in your example it doesn't have.
Generally people design architecture in such method when subscriber class itself hold the object of publisher class. This design has its own benefits in some flow, see below example,
public class EventPublisher
{
public event EventHandler HeavyLogicDone;
public void ExposedMethod(string subScriberSpecificData)
{
Thread logicCaller = new Thread(() => HeavyLogic(subScriberSpecificData));
logicCaller.Start();
}
private void HeavyLogic(string subScriberSpecificData)
{
//logic which may take time
if (HeavyLogicDone != null)
HeavyLogicDone(this, new EventArgsClass(subScriberSpecificData));
}
}
here EventPublisher class has a publicly exposed functionality, which should be called by EventSubscriber , but as this method may take time, it is being written in thread.
Now problem, as it is in thread, call of this method will return soon after starting the thread, subscriber can not start its functionality which is dependent on this method's result, it must wait. So to notify subscriber that task has been done, there is an event.
public class EventSubscriber
{
string currentData = "";
public EventSubscriber(EventPublisher eventPublisher, string data)
{
currentData = data;
eventPublisher.HeavyLogicDone += eventPublisher_HeavyLogicDone;
eventPublisher.ExposedMethod(currentData);
//Contineous without waiting for heavy logic to compelete
}
void eventPublisher_HeavyLogicDone(object sender, EventArgs e)
{
if(((EventArgsData)e).subScriberSpecificData == currentData)
{
//Do further task which is dependant to result of logic
//if now subscriber doesn't need to listen this event anymore
((EventPublisher)sender).HeavyLogicDone -= eventPublisher_HeavyLogicDone;
}
}
}
As you can seen when to subscribe an event and when to unsubscribe it, subscriber has all control now.
But, if you would be doing like this.
static void Main(string[] args)
{
EventSubscriber subscriber1 = new EventSubscriber("sub1");
EventSubscriber subscriber2 = new EventSubscriber("sub2");
EventPublisher pub = new EventPublisher();
pub.HeavyLogicDone += subscriber1.eventPublisher_HeavyLogicDone;
pub.HeavyLogicDone += subscriber2.eventPublisher_HeavyLogicDone;
pub.ExposedMethod("sub1");
pub.ExposedMethod("sub2");
}
First problem : As you can see, every time you are creating an instance of Subscriber, you have to explicitly write it's subscription and calling of publisher's method for current subscriber. that is coupled code, and you need to keep doing this every time.
and subscriber class
public class EventSubscriber
{
string currentData = "";
public EventSubscriber(string data)
{
currentData = data;
}
public void eventPublisher_HeavyLogicDone(object sender, EventArgs e)
{
if(((EventArgsData)e).subScriberSpecificData == currentData)
{
//Do further task which is dependant to result of logic
//if now subscriber doesn't need to listen this event anymore
((EventPublisher)sender).HeavyLogicDone -= eventPublisher_HeavyLogicDone;
}
}
}
Second problem : as subscription is not in control of subscriber class, and unsubscribing can be done only withing subscriber class. Code will be little mess to understand.
I am kind of new to programming in this manner - is there a way that I can work around or a recommended practice to using events and handlers?
eg:
class objectA
{
public List<Handler> handlers;
...
public onActionHappened
{
foreach(Handler h in handlers)
{
raiseEvent(this, eventArgs);
}
}
...
public void DeleteThis()
{
handlers = null
}
}
raiseEvent() will go on an call a few other methods, one of which will invoke DeleteThis(). When everything ends and the program flow returns back to raiseEvent() at the "}" for the foreach loop, it finds that handler has been modified = null, thus throwing the error of InvalidOperationException.
Some method handling should disable this objectA as part of the functionality - thus Deletethis() MAY be called by client code at some point. To fix this, I had modified from List handlers to just a single Handler object, but I feel that that should be a better way of workaround. Or better way of coding.
Any advice? Thanks in advance!
If you use ToArray on the list, you create a copy of its contents and are not dependant on the handler variable itself:
foreach(Handler h in handlers.ToArray()
{
//optional break if you don't want the loop to continue after DeleteThis is called: if(handlers==null)break;
raiseEvent(this, eventArgs);
}
To address the core of your question: The most straightforward way to fix the issue is to assign the list to a local variable before enumerating over it.
class objectA
{
public List<Handler> handlers;
...
public void OnActionHappened()
{
List<Handler> lh = handlers;
// TODO: Would probably make sense to check if lh is null here.
foreach(Handler h in lh)
{
h.raiseEvent(this, eventArgs);
}
}
...
public void DeleteThis()
{
handlers = null;
}
}
There is really no need to create a copy of the list as suggested elsewhere.
Since you seem to be new to C# programming, let me give you some idea what is going on here.
List<T> is a reference type. Let us assume that you create a new List<T> by calling its constructor:
List<Handler> handlers = new List<Handler>();
Now, executing this statement creates two things in the computer's memory:
The list object itself.
A variable ("handlers") that refers to the list object.
Now, if the computer executes the following line:
List<Handler> lh = handlers;
we end up with something like this:
Finally, if the computer executes the following line:
handlers = null;
the situation looks as follows:
As you can see, this way we maintain a valid reference to the list object via the local list variable "lh" and setting the member variable "handlers" to null doesn't affect the foreach enumeration any longer.
An event cannot be triggered outside the class in which the event is defined. So, if you move handlers outside class A, you can no more trigger events in handlers in the class A.
To work around this issue, put handlers in another class, say class B, and define a public method that triggers the events in the handlers in the class B (in this case, the onActionHappened method). For class A, simply call that public method (onActionHappened) of the class B.
I'm working on a winforms application that is very complicated, and has massive callback chains being passed around all over the place.
As an example loosely based on this code, there could be a "Manager" class, that spawns a class "SetUpWorkerThreads" class, which creates a "HandleWorker" thread for say 10 workers.
The worker thread needs to call back to the manager class on occasion, to achieve this the code looks like this:
public class Manager
{
public delegate void SomethingHappenedHandler();
private void Init()
{
var x = new SetUpWorkerThreads(SomethingHappened);
}
private void SomethingHappened()
{
// Handle something happened
}
}
public class SetUpWorkerThreads
{
private readonly Manager.SomethingHappenedHandler _somethingHappened;
public SetUpWorkerThreads(Manager.SomethingHappenedHandler somethingHappened)
{
_somethingHappened = somethingHappened;
}
public void SetupTheThreads()
{
// Contrived!
for (int x=0; x<10; x++)
{
var worker = new Worker(_somethingHappened);
new Thread(worker.DoingSomething).Start();
}
}
}
public class Worker
{
private readonly Manager.SomethingHappenedHandler _somethingHappened;
public Worker(Manager.SomethingHappenedHandler somethingHappened)
{
_somethingHappened = somethingHappened;
}
public void DoingSomething()
{
// ... Do Something
_somethingHappened();
}
}
In reality, there can be many more classes involved, each passing around a mass of callbacks for various things. I realise that poor class/application design is playing a part in this, but are there better ways to go about handling these interactions between classes, specifically in winforms apps, and when a lot of threading is going on?
I can't see that the threading makes it more or less problematic.
One alternative is to use events instead of callbacks, but that won't break up the long chains and will give you an unsubscribing hell too.
One possible approach is to create an object responsible for handling all the events. Either as a singleton or as a single object that you pass to all your threads (instead of the callbacks). Then you can have a simple interface on the EventRouter object to raise events from the threads. You can then subscribe to events on the EventRouter where you need to handle "something happened".
Edit
Something the GoF pattern Mediator but with a publisher-subscriber twist.
Iam writing an app that shows a list of the remaining time a user has on a course.
I want the list to dynamically update every second so the user has the full overview.
public class ReservationCustomerList : INotifyPropertyChanged
{
public int UnitsLeft { get; set; }
public DateTime? OnCircuitSince { get; set; }
public TimeSpan? TimeLeftDate
{
get
{
if (OnCircuitSince.HasValue)
return TimeSpan.FromSeconds((OnCircuitSince.Value - DateTime.Now).TotalSeconds - UnitsLeft);
return TimeSpan.FromSeconds(UnitsLeft);
}
}
private void FireEverySecond()
{
PropertyChanged.Fire(this, x => x.TimeLeftDate);
}
}
As you can see above the idea is that the model knows when the customer entered the circuit and the time the have left.
As you can see iam thinking of using the INotifyPropertyChanged interface and then actually having a timer on every viewmodel.
However this is my concern. Adding a Timer on every viewmodel seems very bloated, is this really the best way to achieve this ?
Second concern is that if the timer is never stopped wouldn't this result in a memory leak since the timer would never stop and keep the viewmodel alive ?
If this is the case my Viewmodel would also need to implement IDisposable and i would need to remember to run through all viewmodels and dispose them to make sure that these are garbage collected. Are my concerns correct ?
Thanks.
Yes i was thinking of having a timer service to prevent having multiple timers, however having to manually unregister would surely at some point introduce memoery leaks.
So the idea with Weak Events is great.
Iam thinking of doing it something like this:
public class TimerService
{
static Timer Timer;
static FastSmartWeakEvent<EventHandler> _secondEvent = new FastSmartWeakEvent<EventHandler>();
static FastSmartWeakEvent<EventHandler> _minuteEvent = new FastSmartWeakEvent<EventHandler>();
static DateTime LastTime;
public static event EventHandler SecondEvent
{
add { _secondEvent.Add(value); }
remove { _secondEvent.Remove(value); }
}
public static event EventHandler MinuteEvent
{
add { _minuteEvent.Add(value); }
remove { _minuteEvent.Remove(value); }
}
static TimerService()
{
Timer = new Timer(TimerFire, null, 1000, 1000);
}
static void TimerFire(object state)
{
_secondEvent.Raise(null, EventArgs.Empty);
if (LastTime.Minute != DateTime.Now.Minute)
_minuteEvent.Raise(null, EventArgs.Empty);
LastTime = DateTime.Now;
}
}
Do you have any comments ?
I Know i could use a singleton GetInstance (or IoC) however this would just make it more inconvinient to use.
Iam using the WeakEvent implementation that Daniel Grunwald wrote on codeproject. (it gives a very clean class and not much overhead).
http://www.codeproject.com/KB/cs/WeakEvents.aspx
You could have a timer service with a private timer and a public event, that notifies all the viewmodels every second.
Regarding the memory issues, you could register your viewmodel with the timer service when your page is navigated (OnNavigatedTo) and unregister it when the view is closed (OnNavigatedFrom). This way the viewmodels wouldn't have any reference with the timer service when they go out of scope, and they would be garbage collected properly.
I have a model class with an event which I subscribe from other classes. I want to subscribe and un-subscribe in each class correctly.
First I want to guarantee that in MyClass I unsibscribe only once even that code is in few methods.
Second there are other classes except MyClass witch use OnMyEvent so I don't want to unintentionally unsibscribe from the event in the class.
MyClass(IModel model)
{
_model = model;
_model.OnMyEvent +=EventHandle;
}
Close()
{
_model.OnMyEvent -=EventHandle;
}
Disconnect()
{
//I want to check if OnMyEvent has already unsibscribed
//Moreover OnMyEvent is used in other classes and
//I don't want to mess up with it here
_model.OnMyEvent -=EventHandle;
}
If you only subscribe once, it doesn't matter how many times you unsubscribe - unsubscribing when you don't have a subscription is a no-op. Equally, the entire point of the event API is that you can't accidentally unsubscribe other subscriptions (either other types, or other instances of the same type).
As such, the code as shown should be fine, although it might be worth moving the two calls to a single method that handles this. That might be overkill, though.
Also, if your type is IDisposable, make sure it gets called in that code-path too (presumably by calling Close()).
You can safely unsubscribe the same handler from an event multiple times. Additional checking is not required and would be contraproductive.
If you want to guarantee you only unsubscribe once, you can use the GetInvocationList method:
if (_model.OnMyEvent != null && _model.GetInvocationList().Contains(EventHandle))
{
_model.OnMyEvent -= EventHandle
}
But as mentioned by the others, you can unsubscribe multiple times. If this really isn't a problem, keep it that way. The solution I propose is just code-noise. Simply unsubscribing in one line is much neater, and easier to read when your class starts to grow.
You can also control subscriptions and unsubsriptions with this declaration. But you also have to iterate through dictionary and call manually subscribed delegates.
private Dictionary<string, EventHandler> TestEvents { get; }
public event EventHandler TestEvent
{
add
{
string name = value.GetType().FullName;
if (!TestEvents.ContainsKey(name))
{
TestEvents.Add(name, value);
}
}
remove
{
string name = value.GetType().FullName;
if (TestEvents.ContainsKey(name))
{
TestEvents.Remove(name);
}
}
}