我一直在开发一些不同的游戏事件系统,其中侦听器接收到一般事件类型对象,并且必须将其真实类型与开关或类似物区分开,然后转换为正确的子类事件。
在不同的aproaches之后,我能够使用如下结构(简化)摆脱开关盒:
public class Event {}
public class EventA : Event {}
public class EventB : Event {}
public delegate void HanlderDelegate(Event ev);
public class EventManager
{
Dictionary<Type, HanlderDelegate> delegateMap = new Dictionary<Type, HanlderDelegate>();
public void Dispatch(Event ev)
{
if (delegateMap.ContainsKey(ev.GetType()))
{
delegateMap[ev.GetType()].Invoke(ev);
}
}
public void Register<T>(HanlderDelegate handler) where T : Event
{
delegateMap.Add(typeof(T), handler);
}
}
public class EventListener
{
public EventListener(EventManager evtMgr)
{
evtMgr.Register<EventA>(this.HandleEventA);
evtMgr.Register<EventB>(this.HandleEventB);
}
public void HandleEventA(Event ev)
{
EventA evA = (EventA)ev;
//... do stuff
}
public void HandleEventB(Event ev)
{
EventB evB = (EventB)ev;
//... do stuff
}
}
我对这种方法很满意,但我仍然发现每种方法中的转换都是可以改进的。我试图让委托更通用
public delegate void HanlderDelegate<T>(T ev) where T : Event;
因此,听众可以直接实施public void HandleEvent(EventA ev)
和public void HandleEvent(EventB ev)
并注册。
但是,当然,EventManager类中的字典应存储指向HanlderDelegate<Event>
的指针,并且存在问题开始的地方,我无法将HanlderDelegate<EventA>
强制转换为HanlderDelegate<Event>
以便存储它们,并且同时存在时间以另一种方式来调用它们。
有没有办法实现这个目标?我知道编译器会允许奇怪的东西,但我知道它并且可以通过代码控制EventB没有错误地被转换到EventA等等。
提前谢谢!
答案 0 :(得分:0)
您可以将委托和Dispatch
方法设为通用,并将处理程序存储为Delegate
而不是HandlerDelegate<T>
:
delegate void HandlerDelegate<TEvent>(TEvent ev) where TEvent : Event;
class EventManager
{
Dictionary<Type, Delegate> delegateMap = new Dictionary<Type, Delegate>();
public void Dispatch<TEvent>(TEvent ev) where TEvent : Event
{
Delegate d;
if (delegateMap.TryGetValue(typeof(TEvent), out d))
{
var handler = (HandlerDelegate<TEvent>)d;
handler(ev);
}
}
public void Register<TEvent>(HandlerDelegate<TEvent> handler) where TEvent : Event
{
delegateMap.Add(typeof(TEvent), handler);
}
}
当然,您仍然必须使用Dispatch
方法,但此时您知道演员阵容是正确的。