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
}
}
Related
I had the idea of developing a class to manage events unsubscriptions in a safe way so I don't have to manually write -= to each event subscription of this system when the time comes (in this system there are groups of events that are subscribed and unsubscribed together).
I thought of creating a class that manages a Dictionary where the key is an event (any possible event) and the value is a method (any possible method). This way I would have a method to subscribe a function to an event and it will do that alongside registering the pair in the Dictionary; and another method to unsubscribe all events added with this class (which would just iterate the dictionary and unsubscribe all events).
Thing is: I can't find how to have a common type of any event that I could use as generic argument to the dictonary's key and also I don't know how to represent any function in C# to set as the dictionary's value. In C/C++ I could just treat them both as void pointers as all I would need is the pointer of the function itself.
Is that even possible to do using C#? Are there existing better methods/strategies to accomplish that?
You will have to come up with a way of generating the key for the event, since you can't use a plain event as a dictionary key. One way to do that would be to concatenate the event's declaring class name with the name of the event.
Then you could use a dictionary using that as a key, with a List<Action> as the value. Here, the Action would be a delegate that you could call to unsubscribe.
You could wrap that dictionary in a class to provide Subscribe() and Unsubscribe() methods like so:
using System;
using System.Collections.Generic;
namespace ConsoleApp2
{
class Program
{
static void Main()
{
string eventKey = test.GetType().FullName + '.' + nameof(test.MyEvent);
subs.Subscribe(eventKey, () => test.MyEvent += handler, () => test.MyEvent -= handler);
subs.Subscribe(eventKey, () => test.MyEvent += handler, () => test.MyEvent -= handler);
test.RaiseEvent(); // Two handlers called.
subs.Unsubscribe(eventKey);
test.RaiseEvent(); // No handlers called (both were unsubscribed).
}
static void handler(object sender, EventArgs args)
{
Console.WriteLine("Handling event.");
}
static readonly Test test = new Test();
static readonly EventSubscriptions subs = new EventSubscriptions();
}
public class EventSubscriptions
{
public void Subscribe(string key, Action subscribe, Action unsubscribe)
{
subscriptions.TryGetValue(key, out var subs);
if (subs == null)
{
subs = new List<Action>();
subscriptions.Add(key, subs);
}
subscribe();
subs.Add(unsubscribe);
}
public void Unsubscribe(string key)
{
subscriptions.TryGetValue(key, out var subs);
if (subs != null)
{
foreach (var unsub in subs)
{
unsub();
}
subscriptions.Remove(key);
}
}
readonly Dictionary<string, List<Action>> subscriptions = new Dictionary<string, List<Action>>();
}
class Test
{
public event EventHandler<EventArgs> MyEvent;
public void RaiseEvent()
{
MyEvent?.Invoke(this, EventArgs.Empty);
}
}
}
Assuming all of your event handlers are of the void MyHandler(object sender, EventArgs e) variety, your dictionary would be Dictionary<string, Action<object,EventArgs>> (assuming you wanted the key to be string - anything else would work too)
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 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?
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 am experimenting with calling delegate functions from a delegate array. I've been able to create the array of delegates, but how do I call the delegate?
public delegate void pd();
public static class MyClass
{
static void p1()
{
//...
}
static void p2 ()
{
//...
}
//...
static pd[] delegates = new pd[] {
new pd( MyClass.p1 ),
new pd( MyClass.p2)
/* ... */
};
}
public class MainClass
{
static void Main()
{
// Call pd[0]
// Call pd[1]
}
}
EDIT: The reason for the array is that I need to call the delegate functions by an index as needed. They are not run in response to an event. I see a critical (stupid) error in my code as I had tried to execute the delegate function using the pd[] type rather than the name of the array (delegates).
If they're all the same type, why not just combine them into a single multicast delegate?
static pd delegateInstance = new pd(MyClass.p1) + new pd(MyClass.p2) ...;
...
pd();
public class MainClass
{
static void Main()
{
pd[0]();
pd[1]();
}
}
In .Net, any delegate is in fact actually a "multicast" delegate (it inherits from this built-in base class), and therefore contains an internal linked list which can contain any number of target delegates.
You can access this list by calling the method GetInvocationList() on the delegate itself. This method returns an array of Delegates...
The only restriction is that all the delegates inside of a given delegate's linked list must have the same signature, (be of the same delegate type). If you need your collection to be able to contain delegates of disparate types, then you need to construct your own list or collection class.
But if this is ok, then you can "call" the delegates in a given delegate's invocation list like this:
public delegate void MessageArrivedHandler(MessageBase msg);
public class MyClass
{
public event MessageArrivedHandler MessageArrivedClientHandler;
public void CallEachDelegate(MessageBase msg)
{
if (MessageArrivedClientHandler == null)
return;
Delegate[] clientList = MessageArrivedClientHandler.GetInvocationList();
foreach (Delegate d in clientList)
{
if (d is MessageArrivedHandler)
(d as MessageArrivedHandler)(msg);
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
pd[0]();
pd[1]();
}
public delegate void delegates();
static delegates[] pd = new delegates[]
{
new delegates(MyClass.p1),
new delegates(MyClass.p2)
};
public static class MyClass
{
public static void p1()
{
MessageBox.Show("1");
}
public static void p2()
{
MessageBox.Show("2");
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
pd[0](1);
pd[1](2);
}
public delegate void delegates(int par);
static delegates[] pd = new delegates[]
{
new delegates(MyClass.p1),
new delegates(MyClass.p2)
};
public static class MyClass
{
public static void p1(int par)
{
MessageBox.Show(par.ToString());
}
public static void p2(int par)
{
MessageBox.Show(par.ToString());
}
}
}