这并不是很难,但需要一定的代码和一些反射。基本想法是将处理程序包装在一个泛型类中,该类由事件类型参数化。
HandlerFor<T> : IDisposable where T : EventArgs.
这个类有一个私有的成员函数,其签名与所需的事件处理程序相匹配:
void Handle(object sender, T eventArgs)
它将在构造时注册,在处理时取消注册,并在事件发生时调用其构造函数中提供的给定
Action
。
为了隐藏实现细节,并仅公开
IDisposable
作为受控事件处理程序生命周期范围和注销的句柄,我将其包装在一个
EventHandlerRegistry
类中。这也将允许添加未来的改进,例如构建工厂委托而不是重复调用
Activator.CreateInstance()
来构建
HandleFor
实例。
它看起来像这样:
public class EventHandlerRegistry : IDisposable
{
private ConcurrentDictionary<Type, List<IDisposable>> _registrations;
public EventHandlerRegistry()
{
_registrations = new ConcurrentDictionary<Type, List<IDisposable>>();
}
public void RegisterHandlerFor(object target, EventInfo evtInfo, Action eventHandler)
{
var evtType = evtInfo.EventHandlerType.GetGenericArguments()[0];
_registrations.AddOrUpdate(
evtType,
(t) => new List<IDisposable>() { ConstructHandler(target, evtType, evtInfo, eventHandler) },
(t, l) => { l.Add(ConstructHandler(target, evtType, evtInfo, eventHandler)); return l; });
}
public IDisposable CreateUnregisteredHandlerFor(object target, EventInfo evtInfo, Action eventHandler)
{
var evtType = evtInfo.EventHandlerType.GetGenericArguments()[0];
return ConstructHandler(target, evtType, evtInfo, eventHandler);
}
public void Dispose()
{
var regs = Interlocked.Exchange(ref _registrations, null);
if (regs != null)
{
foreach (var reg in regs.SelectMany(r => r.Value))
reg.Dispose();
}
}
private IDisposable ConstructHandler(object target, Type evtType, EventInfo evtInfo, Action eventHandler)
{
var handlerType = typeof(HandlerFor<>).MakeGenericType(evtType);
return Activator.CreateInstance(handlerType, target, evtInfo, eventHandler) as IDisposable;
}
private class HandlerFor<T> : IDisposable where T : EventArgs
{
private readonly Action _eventAction;
private readonly EventInfo _evtInfo;
private readonly object _target;
private EventHandler<T> _registeredHandler;
public HandlerFor(object target, EventInfo evtInfo, Action eventAction)
{
_eventAction = eventAction;
_evtInfo = evtInfo;
_target = target;
_registeredHandler = new EventHandler<T>(this.Handle);
_evtInfo.AddEventHandler(target, _registeredHandler);
}
public void Unregister()
{
var registered = Interlocked.Exchange(ref _registeredHandler, null);
if (registered != null)
_evtInfo.RemoveEventHandler(_target, new EventHandler<T>(this.Handle));
}
private void Handle(object sender, T EventArgs)
{
if (_eventAction != null)
_eventAction();
}
public void Dispose()
{
Unregister();
}
}
}
它支持以相当透明的方式清晰地添加和删除事件处理程序。注意:这还没有按推荐的方式实现IDisposable。您需要自己添加终结器和Dispose(bool isFinalizing)方法。
以下是其用法示例:
public class MyArgs1 : EventArgs
{
public string Value1;
}
public class MyEventSource
{
public event EventHandler<MyArgs1> Args1Event;
public EventInfo GetEventInfo()
{
return this.GetType().GetEvent("Args1Event");
}
public void FireOne()
{
if (Args1Event != null)
Args1Event(this, new MyArgs1() { Value1 = "Bla " });
}
}
class Program
{
public static void Main(params string[] args)
{
var myEventSource = new MyEventSource();
using (var handlerRegistry = new EventHandlerRegistry())
{
handlerRegistry.RegisterHandlerFor(
myEventSource,
myEventSource.GetEventInfo(),
() => Console.WriteLine("Yo there's some kinda event goin on"));
handlerRegistry.RegisterHandlerFor(
myEventSource,
myEventSource.GetEventInfo(),
() => Console.WriteLine("Yeah dawg let's check it out"));
myEventSource.FireOne();
}
myEventSource.FireOne();
}
}
运行时,将会输出以下内容:
myObject.SomeEvent += (a, b) => Foo();
)无法在没有先前提到的反射的情况下被删除。使用lambda作为事件处理程序的缺点可以得到缓解,并不意味着这些缺点不存在,也不意味着使用lambda作为事件处理程序是一个好习惯。 - Oblivious Sage