c# - 等待事件触发的可重用类

标签 c# events reflection

我知道这与这里的问题略有重复: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 注册为该事件的处理程序。问题是,事件有不同的签名,我希望能够处理事件,而不管使用的委托(delegate)是什么。

我可以使用 this._event.EventHandlerType 获取委托(delegate)的类型,但是无论委托(delegate)是什么,我如何使用它来创建一个完全可重用的类?如果 DynamicCaller 参数与事件委托(delegate)参数不完全相同,我会得到一个异常。

附带说明一下,我对框架中的代码进行了大量研究,如果我可以访问其中的一些代码,我认为这会很容易。太糟糕了,我需要的很多类都在框架内部。

最佳答案

由于遵循推荐模式的所有事件都有一个对象类型的参数和一个派生自 EventArgs 的类型的参数,您应该能够使用此签名处理所有这些事件:

void DynamicCaller(object sender, EventArgs e)

当然它不适用于非标准事件签名...


编辑:这是一个动态生成的处理程序的示例:

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()
    {
        Delegate handler = CreateHandler();

        _event.AddEventHandler(_eventContainer, handler);

        _autoResetEvent.WaitOne();

        _event.RemoveEventHandler(_eventContainer, handler);

    }

    private Delegate CreateHandler()
    {
        var invokeMethod = _event.EventHandlerType.GetMethod("Invoke");
        var invokeParameters = invokeMethod.GetParameters();
        var handlerParameters = invokeParameters.Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray();
        var body = Expression.Call(Expression.Constant(_autoResetEvent), "Set", null);
        var handlerExpression = Expression.Lambda(_event.EventHandlerType, body, handlerParameters);
        return handlerExpression.Compile();
    }
}

编辑:SLaks 比我快;)

关于c# - 等待事件触发的可重用类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11924328/

相关文章:

C# - 在不同的线程中添加 UserControl 即使在调用之后也会导致异常

php - Laravel:当用户表中的特定列发生变化时如何触发事件?

jquery - jQuery.ready 对文档以外的其他东西有用吗?

java - 执行时确定实例字段类型的通用参数

php - 获取调用函数参数

reflection - 是否可以使用其中一种方法获取结构的名称?

c# - LabelFor不显示值?

c# - 对于我按下的每个按钮,打开相同的表单。(C#)

C++ 事件处理

c# - 将 C# 代码转换为 VB.net