I am trying to create a class to queue up a series of commands. (Not really a queue as events happen based on time). Each command has a callback (Action) that get's called. However, each Action has a different set of parameters (signature), so I am using an object[] to pass them and then have to do lots of casting.
Example: the Queue class:
class RfxQueue {
public enum CMD {DISPLAY, REPLACE_TMPLT, SCALE_DVE, etc };
private Dictionary<CMD, Action<object []>> actions = new Dictionary<CMD,Action<object[]>>();
// Struct to hold command info
public struct QItem
{
public CMD cmd; // The CMD to exec
public long ttd; // Time to be executed
public object[] param; // Parameters to Action
}
private List<QItem> q = new List<QItem>(); // The queue of events
// Create a new callback
public void addAction(CMD cmd, Action<object []> action)
{
actions.Add(cmd, action);
}
// Add to Q
public void pushEvent(CMD Cmd, float Delay, params object[] Param)
{
q.Add(new QItem() { cmd = Cmd, param = Param, ttd = DateTime.Now.AddMilliseconds(Delay * 1000).Ticks });
}
// This is actually done in a thread. Simplified here
private void execEvent()
{
QItem item;
// item is pulled from q here
actions[item.cmd].Invoke(item.param);
}
}
And the owner class creates events like this:
// "q" is a RfxQueue and the internal Invoke is required to run on main thread
q.events.Add(RfxQueue.CMD.SCALE_DVE, new Action<object[]>(o =>
{
dispatcher.Invoke(new Action<string, string, bool>((a,b,c) =>
{
_cgManager.ScaleDVE(a, b, c);
}), (string)o[0], (string)o[1], (bool)o[2]);
}));
q.events.Add(RfxQueue.CMD.PLAY_ANIMATION, new Action<object[]>(o =>
{
dispatcher.Invoke(new Action<VideoTemplate, string>((v, s) => {
_cgManager.playAnimation(v, s);
}), (VideoTemplate)o[0], (string)o[1]);
}));
Lastly, an event is added like this:
// Play animation "inserton" in 3 seconds
q.add(RfxQueue.CMD.PLAY_ANIMATION, template, 3f, "inserton");
Is there a way to do this without all that casting? Thanks!