C#根据参数类型订阅事件
本文关键字:事件 类型 参数 | 更新日期: 2023-09-27 18:28:53
我有一个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>
类型。
如何干净地实现这一点?
谢谢!
试试这个
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; }
}
}