C# 聚合事件源和重新修补事件的最佳方法
我试图找到创建一个系统的最佳方法,在这个系统中,可以将事件源添加到管理器类,然后管理器类会将它们的事件重新分派给侦听器。具体来说,我有许多不同的输入源(键盘输入源、鼠标输入源、虚拟键盘输入源等),我希望允许开发人员监听键盘输入源和输入管理器本身上的按键事件(从任何活动输入源捕获此事件) 很容易强行执行一个解决方案,在这个解决方案中,我创建了许多“分派”函数,当事件发生时,只需重新分派事件,但我最终拥有几十个单行函数,每当向输入源接口添加新事件时,我都必须创建新函数 我已经考虑过使用lambdas,但是如果从管理器中删除了输入源,我需要一种方法来取消事件挂钩。我可以将lambda保存在一个字典中,由输入源设置关键字,但许多事件都有不同的arg类,因此创建多个字典来实现这一点开始变得很糟糕 我想知道我是否缺少了一些简单的方法来做到这一点,它可以保持事情的整洁,并保持我需要写下的额外代码的数量 以下是我正在使用的对象示例,仅供参考:C# 聚合事件源和重新修补事件的最佳方法,c#,events,architecture,lambda,C#,Events,Architecture,Lambda,我试图找到创建一个系统的最佳方法,在这个系统中,可以将事件源添加到管理器类,然后管理器类会将它们的事件重新分派给侦听器。具体来说,我有许多不同的输入源(键盘输入源、鼠标输入源、虚拟键盘输入源等),我希望允许开发人员监听键盘输入源和输入管理器本身上的按键事件(从任何活动输入源捕获此事件) 很容易强行执行一个解决方案,在这个解决方案中,我创建了许多“分派”函数,当事件发生时,只需重新分派事件,但我最终拥有几十个单行函数,每当向输入源接口添加新事件时,我都必须创建新函数 我已经考虑过使用lambdas
public interface IInputSource {}
public interface IKeyboardInputSource : IInputSource
{
event EventHandler<KeyboardEventArgs> KeyDown;
event EventHandler<KeyboardEventArgs> KeyUp;
}
public interface IMouseInputSource : IInputSource
{
event EventHandler<MouseEventArgs> MouseDown;
event EventHandler<MouseEventArgs> MouseUp;
}
public class InputManager : IKeyboardInputSource, IMouseInputSource
{
private List<IInputSource> InputSources;
//Event declarations from IKeyboardInputSource and IMouseInputSource
public void AddSource(IInputSource source)
{
InputSources.Add(source);
if (source is IKeyboardInputSource)
{
var keyboardSource = source as IKeyboardInputSource;
keyboardSource.KeyDown += SendKeyDown;
// Listen for other keyboard events...
}
if (source is IMouseInputSource)
{
// Listen for mouse events...
}
}
public void RemoveSource(IInputSource source)
{
if (source is IKeyboardInputSource)
{
var keyboardSource = source as IKeyboardInputSource;
keyboardSource.KeyDown -= SendKeyDown;
// Remove other keyboard events...
}
if (source is IMouseInputSource)
{
// Remove mouse events...
}
InputSources.Remove(source);
}
private void SendKeyDown(object sender, KeyboardEventArgs e)
{
if (KeyDown != null)
KeyDown(sender, e);
}
//Other "send" functions
}
公共接口IIInputSource{}
公共接口IKeyboardInputSource:IIInputSource
{
事件处理键关闭;
事件处理程序键控;
}
公共接口IMouseInputSource:IInputSource
{
事件处理程序MouseDown;
事件处理程序MouseUp;
}
公共类输入管理器:IKeyboardInputSource、IMouseInputSource
{
私人列表输入源;
//来自IKeyboardInputSource和IMouseInputSource的事件声明
public void AddSource(IInputSource源)
{
输入源。添加(源);
if(源为IKeyboardInputSource)
{
var keyboardSource=源为IKeyboardInputSource;
keyboardSource.KeyDown+=SendKeyDown;
//侦听其他键盘事件。。。
}
if(源为IMouseInputSource)
{
//侦听鼠标事件。。。
}
}
公共void RemoveSource(IIInputSource源)
{
if(源为IKeyboardInputSource)
{
var keyboardSource=源为IKeyboardInputSource;
keyboardSource.KeyDown-=SendKeyDown;
//删除其他键盘事件。。。
}
if(源为IMouseInputSource)
{
//删除鼠标事件。。。
}
输入源。删除(源);
}
私有void SendKeyDown(对象发送方,KeyboardEventArgs e)
{
if(KeyDown!=null)
按下键(发送器,e);
}
//其他“发送”功能
}
您看过(Rx)框架了吗?看起来它将满足您的要求,并为您提供了一个功能丰富的/类似lambda的api来管理和处理事件
反应式扩展(Rx)是一个库,用于使用可观察序列和LINQ样式的查询运算符编写异步和基于事件的程序
可能类似的东西会有所帮助-这是一种通用方法,既可以直接订阅事件,也可以通过“接收器”接口
interface IInputSource<T> where T : EventArgs
{
event EventHandler<T> InputEvent;
}
interface IInputSink<in T> where T : EventArgs
{
void InputMessageHandler(object sender, T eventArgs);
}
internal class InputManager
{
private Dictionary<Type, object> _inputSources;
private Dictionary<Type, object> _inputSinks;
private Dictionary<Type, object> _events;
public void AddSource<T>(IInputSource<T> source) where T : EventArgs
{
_inputSources[typeof(T)] = _inputSources; //add source
_events[typeof(T)] = (EventHandler<T>)Dispatch; //register event for subscribers
source.InputEvent += Dispatch;
source.InputEvent += Dispatch2;
}
// Dispatch trough direct event subscriptions;
private void Dispatch<T>(object sender, T e) where T : EventArgs
{
var handler = _events[typeof(T)] as EventHandler<T>;
handler.Invoke(sender, e);
}
// Dispatch trough IInputSink subscriptions;
private void Dispatch2<T>(object sender, T e) where T : EventArgs
{
var sink = _inputSinks[typeof(T)] as IInputSink<T>;
sink.InputMessageHandler(sender, e);
}
//Subscription: Client should provide handler into Subscribe()
//or subscribe with IInputSink<MyEvent> implementation (Subscribe2())
public void Subscribe<T>(EventHandler<T> handler) where T : EventArgs
{
var @event = _events[typeof(T)] as EventHandler<T>;
_events[typeof(T)] = @event + handler;
}
public void Subscribe2<T>(IInputSink<T> sink) where T : EventArgs
{
_inputSinks[typeof(T)] = sink;
}
}
class XXXX : EventArgs
{
}
public class Sink: IInputSink<XXXX>
{
#region Implementation of IInputSink<in XXXX>
public void InputMessageHandler(object sender, XXXX eventArgs)
{
throw new NotImplementedException();
}
#endregion
public Sink()
{
var v = new InputManager();
v.Subscribe<XXXX>(GetInputEvent);
v.Subscribe2(this);
}
private void GetInputEvent(object sender, XXXX xxxx)
{
throw new NotImplementedException();
}
}
接口IIInputSource,其中T:EventArgs
{
事件处理程序InputEvent;
}
接口IIInputSink,其中T:EventArgs
{
void InputMessageHandler(对象发送者,T eventArgs);
}
内部类输入管理器
{
专用词典(inputSources);;
专用字典输入接收器;
私人字典(private Dictionary)事件;;
public void AddSource(IIInputSource源),其中T:EventArgs
{
_inputSources[typeof(T)]=\u inputSources;//添加源
_事件[typeof(T)]=(EventHandler)分派;//为订阅服务器注册事件
source.InputEvent+=调度;
source.InputEvent+=Dispatch2;
}
//通过直接事件订阅发送;
私有void分派(对象发送方,te),其中T:EventArgs
{
var handler=_events[typeof(T)]作为EventHandler;
调用(发送方,e);
}
//通过IIInputSink订阅发送;
私有void Dispatch2(对象发送方,te),其中T:EventArgs
{
变量接收器=_输入接收器[类型(T)]作为IIInputSink;
sink.InputMessageHandler(发送方,e);
}
//订阅:客户端应向Subscribe()提供处理程序
//或者使用IIInputSink实现(Subscribe2())进行订阅
public void Subscribe(EventHandler)其中T:EventArgs
{
var@event=_events[typeof(T)]作为EventHandler;
_事件[typeof(T)]=@event+handler;
}
public void Subscribe2(IIInputSink sink),其中T:EventArgs
{
_输入接收器[类型(T)]=接收器;
}
}
XXXX类:事件参数
{
}
公共类接收器:IInputSink
{
#IInputSink的区域实现
public void InputMessageHandler(对象发送方,XXXX事件参数)
{
抛出新的NotImplementedException();
}
#端区
公共水槽()
{
var v=新的InputManager();
v、 订阅(GetInputEvent);
v、 认购2(本);
}
私有void GetInputEvent(对象发送方,XXXX)
{
抛出新的NotImplementedException();
}
}
我应该在前面提到这一点,但不幸的是,我正在从事的项目不允许我使用任何第三方库。但是,由于BBVComon库是开源的,您可以检查它中使用的代码,然后您可以复制它并使其适应您的代码。这是直接链接到源代码的好点。我去看看!