I have a class that goes like this:
public static class Messenger<T>
{
private static readonly Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
public static void DoSomethingWithEventTable() //Somehow fills eventTable
public static void Clear()
{
eventTable.Clear();
}
}
Now, I called DoSomethingWithEventTable two times somewhere in my program, like this:
Messenger<int>.DoSomethingWithEventTable();
Messenger<float>.DoSomethingWithEventTable();
I want to clear eventTable for every Messenger<T>. How should I do it? Should I call Clear for every type that I have put in generics, like this:
Messenger<int>.Clear();
Messenger<float>.Clear();
Or will it be enough to do something silly like this once:
Messenger<string>.Clear();
UPD: Basic experiments show that I should clear the Messenger for every used T. Now could somebody come with better design for the classes?
The more detailed version of what I am using now:
static public class Messenger<T>
{
private static readonly Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
static public void AddListener(string eventType, Callback<T> handler)
{
// Obtain a lock on the event table to keep this thread-safe.
lock (eventTable)
{
// Create an entry for this event type if it doesn't already exist.
if (!eventTable.ContainsKey(eventType))
{
eventTable.Add(eventType, null);
}
// Add the handler to the event.
eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler;
}
}
static public void RemoveListener(string eventType, Callback<T> handler)
{
// Obtain a lock on the event table to keep this thread-safe.
lock (eventTable)
{
// Only take action if this event type exists.
if (eventTable.ContainsKey(eventType))
{
// Remove the event handler from this event.
eventTable[eventType] = (Callback<T>)eventTable[eventType] - handler;
// If there's nothing left then remove the event type from the event table.
if (eventTable[eventType] == null)
{
eventTable.Remove(eventType);
}
}
}
}
static public void Invoke(string eventType, T arg1)
{
Delegate d;
// Invoke the delegate only if the event type is in the dictionary.
if (eventTable.TryGetValue(eventType, out d))
{
// Take a local copy to prevent a race condition if another thread
// were to unsubscribe from this event.
Callback<T> callback = (Callback<T>)d;
// Invoke the delegate if it's not null.
if (callback != null)
{
callback(arg1);
}
}
}
static public void Clear()
{
eventTable.Clear();
}
}
It is also important that I have another classes Messenger (non-generic, yeah) and Messenger<T,M>, and maybe someday I would even need something like Messenger<T,M,N>, etc.
Each Messenger<T> type will have it's own copy of eventTable so you will need to call Clear() for every different T you have used.
As shown by this test:
[TestFixture]
public class Tests
{
static class MyClass<T>
{
public static List<int> Member = new List<int>();
}
[Test]
public void StaticTest()
{
var m1 = MyClass<int>.Member;
var m2 = MyClass<string>.Member;
Assert.AreNotSame(m1, m2);
}
}
Since
private static readonly Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
does not depend on <T>, create a static "handler" for all event tables.
IE
public static class TableHandler {
ICollection<Dictionary<string, Delegate>> tables = new List<Dictionary<string, Delegate>>();
public void Add(Dictionary<string, Delegate> item)
{
tables.Add(item);
}
public void Clear()
{
foreach (var item in tables) item.Clear();
tables.Clear();
}
}
and ensure that DoSomethingWithEventTable() adds the event table to the TableHandler.
Might not be the best overall solution, but it helps you keep track of the tables with the current design.
EDIT:
I tried to google for a way to find all generic variants of a static class, but I did not find a way. Does anyone know of a way to do that?
Related
Would like to ask how to make a dictionary with delegate.
The idea is:
Have a console based command defined by "/"
use dictionary to store command and del that will invoke the function i need.
What i have so far: I managed to do same by creating events
delegate void CmdHandler(string[] cmdArgs);
class CMDReader
{
public event CmdHandler _Print;
public event CmdHandler _Help;
private char cmdChar;
}
cmdReader._Print += new CmdHandler(Print);
void Print(string[] args)
but I am looking for a way to manage it without event. I figured I can do so with dictionary but not sure how to do it.
You can add the delegates to a Dictionary, and then using an indexer key (I've just assumed the name of the command here) to Invoke the appropriate action. The problem with this pattern however is the loose typing on the arguments (All string[], with implied knowledge about the meaning of each), and the restriction on a common return type from all methods (currently void).
public class CMDReader
{
delegate void CmdHandler(string[] cmdArgs); // Or Action<string[]>
private readonly IDictionary<string, CmdHandler> _commands;
public CMDReader()
{
_commands = new Dictionary<string, CmdHandler>
{
{
"Print", Print
},
{
"Help", Help
},
};
}
public void InvokeCommand(string command, string[] args)
{
if (_commands.ContainsKey(command))
{
_commands[command].Invoke(args);
// OR (_commands[command])(args);
}
else
{
Console.WriteLine("I don't know that command ...");
}
}
private void Print(string[] args)
{
// Implementation
}
private void Help(string[] args)
{
// Implementation
}
}
I am making a game and I'm trying to create an way for objects to handle collisions with each other. I want to do something like:
//Imaginary C#
public SomethingThatCollides()
{
CollisionEvent<ObjectA> += CollisionWithObjA;
CollisionEvent<ObjectB> += CollisionWithObjB;
}
void CollisionWithObjA(ObjectA other)
{
//Do something
}
void CollisionWithObjB(ObjectB other)
{
//Do something else
}
When, say, CollisionEvent<ObjectA> is raised (perhaps by some collision checking code), CollisionWithObjA should get called. Same for CollisionWithObjB; when a collision with ObjectB is detected, it will raise the CollisionEvent<ObjectB> event which results in CollisionWithObjB getting called.
Is something like this possible?
Here is the thing, if class is generic and it has static field, it can work like a dictionary with key being type
public class Something {
public class EventsHolder<T>
{
static event Action<T> CollideEvent;
}
public void AddEvent<T>(Action<T> collisionEvent)
{
EventsHolder<T>.CollideEvent = collisionEvent;
}
public void RaiseCollision<T>(T Obj)
{
var Event = EventsHolder<T>.CollideEvent;
if (Event != null) Event(Obj);
}
}
Downside is that it uses static fields which can be inapropriate.
In this case you can use code #Daniel posted.
You can't really create a generic event like that. I suggest you create a special event arguments class that also encapsulates the collided object and check for its type in the event handler method:
public class CollisionEventArgs : EventArgs {
public object Object {
get; private set;
}
// ...
}
You'll need a special dispatcher method to use it:
class SomethingThatCollides {
public SomethingThatCollides(CollisionManager cm) {
cm.CollisionEvent += CollisionWithObj;
}
void CollisionWithObj(object sender, CollisionEventArgs args) {
if (args.Object is ObjectA) {
CollisionWithObjA((ObjectA)args.Object);
}
else if (args.Object is ObjectB) {
CollisionWithObjB((ObjectB)args.Object);
}
}
// ...
}
Or, you can try to solve this with double-dispatching, without using C# events. Look at wikipedia for a collision example.
That's uggly, but...You could have a dicionary of events by type:
Dictionary<Type, object> MyEventsByType;
event Action<A> CollisionEventA;
event Action<B> CollisionEventB;
event Action<C> COllisionEventC;
void Initialize()
{
MyEventsByType = new Dictionary<Type, object>();
MyEventsByType.Add(typeof(A), CollisionEventA);
MyEventsByType.Add(typeof(B), CollisionEventB);
MyEventsByType.Add(typeof(C), CollisionEventC);
}
void RaiseCollision<T>(T Obj)
{
Action<T> Event = (Action<T>)MyEventsByType[typeof(T)];
if (Event != null) Event(Obj);
}
I was looking through some old code today and found an event handler that looked like this:
public void HandleEvent(EventClassA eventObj)
{
if(eventObj is EventSubClassA)
{
HandleEventSubClassA(eventObj as EventSubClassA);
}
else if(eventObj is EventSubClassB)
{
HandleEventSubClassB(eventObj as EventSubClassB);
}
else if(eventObj.GetType() == typeof(EventSubClassC))
{
HandleEventSubClassC(eventObj as EventSubClassC);
}
else if(eventObj is EventSubClassD)
{
HandleEventSubClassD(eventObj as EventSubClassD);
}
}
I thought this was kind of ugly. So I refactored it like this:
delegate void EventHandler(dynamic eventObj);
private static readonly Dictionary<Type, EventHandler> EVENT_MAP = new Dictionary<Type, EventHandler>()
{
{ typeof(EventSubClassA), HandleEventSubClassA },
{ typeof(EventSubClassB), HandleEventSubClassB },
{ typeof(EventSubClassC), HandleEventSubClassC },
{ typeof(EventSubClassD), HandleEventSubClassD }
};
public void HandleEvent(EventClassA eventObj)
{
EVENT_MAP[eventObj.GetType()](eventObj);
}
private void HandleEventSubClassA(dynamic evt)
{
var eventObj = evt as EventSubClassA;
}
I had a coworker review the code and there were concerns about the way this solution worked compared to the previous solution. I have a hard time believing that the previous solution is the best solution for this case, so I've turned to StackOverflow.
Is there a better way to build this type of class?
Is there a pattern I'm not aware of that is designed for this?
You can use generics to make your existing solution slightly safer:
private static Dictionary<Type, Delegate> handlers;
static HandlerClass()
{
handlers = new Dictionary<Type, Delegate>();
AddHandler<EventSubClassA>(HandleEventSubClassA);
AddHandler<EventSubClassB>(HandleEventSubClassB);
...
}
public static void AddHandler<T>(Action<T> handler) where T : EventClassA
{
handlers[typeof(T)] = handler;
}
public void HandleEvent(EventClassA #event)
{
Delegate handler;
if(handlers.TryGetValue(#event.GetType(), out handler))
{
handler.DynamicInvoke(#event);
}
}
Alternatively, if you can modify the classes in your event hierarchy you could implement the visitor pattern:
public interface IHandlers
{
void HandleSubClassA(EventSubClassA a);
void HandleSubClassB(EventSubClassB b);
...
}
public abstract class EventClassA
{
public abstract void Visit(IHandlers handlers);
}
public class EventSubClassA : EventClassA
{
public override void Visit(IHandlers handlers)
{
handlers.HandleSubClassA(this);
}
}
I feel like I'm missing something.
Wouldn't the best way to be to write overloads for each event type?
I'm trying to implement EventArgs to pass a list of parameters to my messaging system: Question.
I subclassed EventArgs:
public class SingleParameterArgs<T> : EventArgs
{
public T arg1;
public SingleParameterArgs(T _arg1)
{
arg1 = _arg1;
}
}
Here's the class and method that should accept the EventArgs:
static public class Messenger<TEventArgs> where TEventArgs : EventArgs {
private static Dictionary< string, EventHandler<TEventArgs> > eventTable = new Dictionary< string, EventHandler<TEventArgs> >();
static public void Invoke(string eventType, TEventArgs args) {
EventHandler<TEventArgs> eventHandler;
if (eventTable.TryGetValue(eventType, out eventHandler)) {
if (eventHandler != null)
eventHandler();
}
}
}
Before implementing EventArgs I would invoke a message in the following way:
Messenger<GameEndingType>.Invoke( "end game", GameEndingType.TimeEnded );
But now it looks much longer and much more complicated:
Messenger< SingleParameterArgs<GameEndingType> >.Invoke( "end game", new SingleParameterArgs<GameEndingType>(GameEndingType.TimeEnded) );
Is it possible to make it look shorter? I don't want to type such a long line every time I need to send a message. Maybe I could create a wrapper?
Something like this would be perfect:
Messenger.Invoke("end game", GameEndingType.TimeEnded);
What is the best way to create a uniform wrapper for a random amount of parameters?
Are you happy for your Messenger class to be tied to SingleParameterArgs<T>? If so, you could use:
// Here TEventArgs represents the element type *within* SingleParameterArgs
public static class Messenger<TEventArgs> {
private static
Dictionary<string, EventHandler<SingleParameterArgs<TEventArgs>> eventTable =
new Dictionary<string, EventHandler<SingleParameterArgs<TEventArgs>>();
public static void Invoke(string eventType, TEventArgs args) {
EventHandler<SingleParameterArgs<TEventArgs>> eventHandler;
if (eventTable.TryGetValue(eventType, out eventHandler)) {
if (eventHandler != null) {
eventHandler();
}
}
}
}
Of course you can have both, with a totally general Messenger class (as per your question), and then a SingleParameterMessenger class which delegates to it:
public static class SingleParameterMessenger<TEventArgs> {
public static void Invoke(string eventType, TEventArgs args) {
Messenger<SingleParameterArgs<TEventArgs>>.Invoke(eventType, args);
}
}
Just as an aside, I'm not really sure this is all a good idea anyway - particularly in terms of static registration, which tends to make testing harder, and certainly needs more care in terms of concurrency. (Your code is currently not threadsafe.)
I made a utility debug class in a C# game I'm working on to be able to monitor and watch values of properties. Goes like this:
public static class Monitor
{
private static List<object> monitoredObjects;
public static void Initialize()
{
monitoredObjects = new List<object>();
}
public static void Watch(object o)
{
monitoredObjects.Add(o);
}
public static void Unwatch(object o)
{
monitoredObjects.Remove(o);
}
public static void Draw(RenderWindow app)
{
//Not actual code, I actually draw this in game
foreach (object o in monitoredObjects)
Console.WriteLine(o.ToString());
}
}
public class Property
{
private object obj;
private PropertyInfo propertyInfo;
public override string ToString()
{
return propertyInfo.Name + ": " + propertyInfo.GetValue(obj, null).ToString();
}
public Property(object o, string property)
{
obj = o;
propertyInfo = o.GetType().GetProperty(property);
}
}
Now in order to monitor a property, say my game's FPS, I must do
Monitor.Watch(new Property(Game, "FPS"));
Wouldn't there be a way to somehow make this simpler to use? Ideally I'd like to be able to do
Monitor.Watch(Game.FPS);
But since we can't store pointers to value types in C#, I don't know how I would do this. Maybe using closures and lambada expressions? I was suggested this earlier but I'm not sure how to do it. Any other ways to improve this?
Thanks
Personally, what I would do is rework your Monitor class to accept a Func<string> as input, and return a monitoring handle that could be used to "unmonitor" the class.
By doing that, you'd be able to write:
var handle = Monitor.Watch( () => Game.FPS.ToString() );
// later
Monitor.Unwatch(handle);
This could look something like:
public static class Monitor
{
private static Dictionary<IMonitorHandle, Func<string>> monitoredObjects;
public static void Initialize()
{
monitoredObjects = new Dictionary<IMonitorHandle, Func<string>>();
}
public static IMonitorHandle Watch(Func<string> o)
{
var handle = new MonitorHandle(o);
monitoredObjects.Add(handle, o);
return handle;
}
public static void Unwatch(IMonitorHandle handle)
{
monitoredObjects.Remove(handle);
}
public static void Draw(RenderWindow app)
{
//Not actual code, I actually draw this in game
foreach (object o in monitoredObjects.Values)
Console.WriteLine(o()); // Execute to get value...
}
}
You'd need to implement some interface for the handle - but this really could be anything, since it's just an object used as a hash table lookup for allowing unsubscription. You only need this to allow "Unwatch" to work, since you need to have some way to remove the delegate, which you'll probably want to define anonymously (as I did above).
Why are you not using INotifyPropertyChanged interface and just fire off the events within the Monitor class, something like this...assume your objects implement the interface...and every property in your objects raise a 'PropertyChanged' event with parameters indicating the values...in that way, it will be a fire and forget solution instead of looping through the list... as you call instantiate 'Monitor' with a 'RenderWindow' used as parameter to 'Initialize'. Also notice that 'Property' class is slightly modified to include a get accessor to return the object in question...
public static class Monitor
{
private static List monitoredObjects;
private static RenderWindow _app;
public static void Initialize(RenderWindow app)
{
monitoredObjects = new List();
}
public static void Watch(object o)
{
monitoredObjects.Add(o);
o.PropertyChanged += new EventHandler(monitor_PropertyChanged);
}
public static void Unwatch(object o)
{
o.PropertyChanged -= new EventHandler(monitor_PropertyChanged);
monitoredObjects.Remove(o);
}
public static monitor_PropertyChanged(object sender, PropertyChangedEventArgs e){
// Not actual code, I actually draw this in game
Console.WriteLine(e.SomeValue);
}
public static void Draw(RenderWindow app)
{
//Not actual code, I actually draw this in game
foreach (object o in monitoredObjects)
Console.WriteLine(o.ToString());
}
}
public class Property
{
private object obj;
private PropertyInfo propertyInfo;
public object PropObj{
get{ return this.obj; }
}
public override string ToString()
{
return propertyInfo.Name + ": " + propertyInfo.GetValue(obj, null).ToString();
}
public Property(object o, string property)
{
obj = o;
propertyInfo = o.GetType().GetProperty(property);
}
}
Hope this helps,
Best regards,
Tom.