有关处理多线程事件中的异常的建议

时间:2011-07-11 09:48:10

标签: c# .net events c#-4.0

我有一个类可以触发委托给DispatcherObject目标的事件,这些事件正在编组,但我遇到的问题是,如果处理程序在其事件代码中抛出异常,我该怎么办?我不想阻止其他侦听器处理该事件。我正在寻找有关如何解决这个问题的建议。

给定一个带有Saved事件的抽象基类,我的模式如下:

public event EventHandler<EventArgs> Saved;
public void Save() {
    try {
        OnSave();
    } catch (Exception) {
        // What should I do here? throwing prevents subsequent handlers,
        // while catching gobbles up the exception. Should this be in OnSave()?
    }
}
protected virtual void OnSave() {
    EventHandler<EventArgs> evt = Saved;
    if (evt != null) {
        var args = EventArgs.Empty;
        foreach (var handler in evt.GetInvocationList()) {
            var target = handler.Target as DispatcherObject;
            if (target == null || target.CheckAccess()) {
                var h = handler as EventHandler<EventArgs>;
                if (h != null) h(this, args);
            } else {
                target.Dispatcher.Invoke(handler, this, args);
            }
        }
    }
}

我考虑过构建一个包含ArrayException之类的所有异常的异常,但这似乎不对。

非常感谢有关如何做的建议。

更新:我感谢Daniel和Henrik的回答,如果我能将两者都标记为答案,我决定去处理这个事件,因为我真的不想要它完全没有被注意到,我的最终解决方案如下(对于寻找解决方案的其他人)。

public event EventHandler<EventArgs> Saved;
public void Save() {
    OnSave();
}
protected virtual void OnSave() {
    EventHandler<EventArgs> evt = Saved;
    if (evt != null) {
        var args = EventArgs.Empty;
        var handlers = evt.GetInvocationList();
        var exceptions = new Queue<Exception>(handlers.Length);
        foreach (var handler in handlers) {
            try {
                var target = handler.Target as DispatcherObject;
                if (target == null || target.CheckAccess()) {
                    var h = handler as EventHandler<EventArgs>;
                    if (h != null) h(this, args);
                } else {
                    target.Dispatcher.Invoke(handler, this, args);
                }
            } catch (Exception ex) {
                exceptions.Enqueue(ex);
            }
        }
        if (exceptions.Count == 1) {
            var ex = exceptions.Peek();
            throw new Exception(ex.Message, ex);
        }
        if (exceptions.Count > 0) {
            throw new AggregateException(exceptions);
        }
    }
}

2 个答案:

答案 0 :(得分:2)

无需创建自己的ArrayException。您可以使用System.AggregateException包装多个例外。

答案 1 :(得分:1)

从您的代码中,您似乎应该将循环中的调用包装到try / catch中,并在那里插入异常。

我没有看到OnSave调用者如何从所有事件处理程序中获得单个异常中受益。由于你有多个事件句柄,并且从你的架构草图看起来每个人都做了完全不同的事情(因为每个人都必须被调用),异常空间是如此异构,所以调用者无论如何都无法处理它。

所以问题可能是:我如何处理更高级别的多个事件异常?

您可以尝试更正并重新运行OnSave吗?你必须省略成功的电话吗?等等...