C#根据参数类型订阅事件?

时间:2016-01-03 21:17:22

标签: c#

我有一个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>类型。

如何干净利落地实现这一目标?

谢谢!

1 个答案:

答案 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; }
    }
}