我知道这里有点重复:Blocking and waiting for an event
但是,我在编写EventWaiter的过程中遇到了问题.这是我一直在努力的(主要)简化版本:
public class EventWaiter
{
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private EventInfo _event = null;
private object _eventContainer = null;
public EventWaiter(object eventContainer, string eventName)
{
_eventContainer = eventContainer;
_event = eventContainer.GetType().GetEvent(eventName);
}
public void WaitForEvent()
{
MethodInfo method = this.GetType().GetMethod("DynamicCaller");
Delegate handler = Delegate.CreateDelegate(this._event.EventHandlerType, this, method);
_event.AddEventHandler(_eventContainer, handler);
_autoResetEvent.WaitOne();
_event.RemoveEventHandler(_eventContainer, _handler);
}
public void DynamicCaller(/* insert magic here */)
{
_autoResetEvent.Set();
}
}
用法将是:
EventWaiter ew = new EventWaiter(someClass, "someEvent");
ew.WaitForEvent();
基本上发生了什么,就是将DynamicCaller void注册为该事件的处理程序.问题是,事件具有不同的签名,并且我希望能够处理事件,而不管所使用的委托是什么.
我可以使用this._event.EventHandlerType获得委托的类型,但是无论委托是什么,如何使用它来创建完全可重用的类?如果DynamicCaller参数与事件委托参数不完全相同,则会发生异常.
作为附带说明,我做了很多研究框架中的代码的工作,如果我可以访问其中的一些代码,我认为这很容易.太糟糕了,我需要的很多类都在框架内部.
解决方法:
您应该使用表达式树来编译带有调用回调的任意参数的方法:
Expression.Lambda(
_event.EventHandlerType,
Expression.Call(Exrpession.Constant(_autoResetEvent),
typeof(AutoResetEvent).GetMethod("Set")),
_event.EventHandlerType.GetMethod("Invoke")
.GetParameters()
.Select(p => Expression.Parameter(p.ParameterType))
).Compile();
请注意,您可以使用泛型和表达式树使系统类型安全:
new EventWaiter(_ => someObject.SomeEvent += _)
其中_是普通(但简短)参数名称.