我有一个Commander
类,用于处理命令。所有这些命令都实现了ICommand
接口。基本上是命令模式......
现在我想为每种特定类型的命令创建类似于event
的东西,而不是实际为命令器中的每个特定类型创建一个事件。指挥官不应该与每种类型的指挥相结合。
所以我的命令有一个方法void Subscribe<T>(Action<T> callback) where T: ICommand
。如果订户使用方法void MyAttackCommandHandler(AttackCommand att)
作为参数调用此方法,我希望订阅者仅针对AttackCommands
获得回调。但是另一个类也可以订阅不同的命令。
我尝试创建一个字典,将参数的类型(命令类型)映射到订阅者列表:Dictionary<Type, List<Action<ICommand>>> _subscriptions
,然后我的订阅方法看起来像:
public void Subscribe<T>(Action<T> callback)
where T: ICommand
{
Type type = typeof(T);
if (_subscriptions.ContainsKey(type))
{
List<Action<ICommand>> subscribtions = _subscriptions[type];
subscribtions.Add(callback);
}
else ... //create a new entry in _subscriptions
}
然而,这不起作用,因为callback
不是Action<ICommand>
类型,而是Action<AttackCommand>
类型。
如何干净利落地实现这一目标?
谢谢!
答案 0 :(得分:3)
试试这个
subscribtions.Add(i => callback((T)i));
如果以上操作不起作用,请提供一个显示问题的完整示例。 像这样:
using System;
using System.Collections.Generic;
namespace Example
{
class Program
{
static void Main(string[] args)
{
Commander C = new Commander();
C.Subscribe((MyCommand i) => { Console.WriteLine(i.Value); });
C.Subscribe((SquareMyCommand i) => { Console.WriteLine(i.Value); });
C.Subscribe((SquareMyCommand i) => { Console.WriteLine("**" + i.Value + "**"); });
C.Do(new MyCommand(2));//1 callback , Prints 2
C.Do(new SquareMyCommand(3));//2 callbacks, Prints 9 , **9**
Console.ReadLine();
}
}
public class Commander
{
Dictionary<Type, List<Action<ICommand>>> dictionary = new Dictionary<Type, List<Action<ICommand>>>();
public void Subscribe<T>(Action<T> callback) where T : ICommand
{
Type type = typeof(T);
List<Action<ICommand>> subscribtions = null;
dictionary.TryGetValue(type, out subscribtions);
if (subscribtions == null)
{
subscribtions = new List<Action<ICommand>>();
dictionary.Add(type, subscribtions);
}
subscribtions.Add(i => callback((T)i));
}
public void Do<T>(T t) where T : ICommand
{
foreach (var item in dictionary[t.GetType()])
item(t);
}
}
public class MyCommand : ICommand
{
public MyCommand(int x) { Value = x; }
public int Value { get; set; }
}
public class SquareMyCommand : ICommand
{
public SquareMyCommand(int x) { Value = x * x; }
public int Value { get; set; }
}
public interface ICommand
{
int Value { get; set; }
}
}