Рекомендации по обработке исключений в многопоточных событиях - PullRequest
2 голосов
/ 11 июля 2011

У меня есть класс, который запускает события, делегирующие 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 или что-то в этом роде, но это не так.

Советы о том, что делать здесь, будут очень признательны.

ОБНОВЛЕНИЕ : Я благодарю Даниэля и Хенрика за ваши ответы. Если бы я мог пометить оба ответа, как и я, я решил бы заняться обработкой события, поскольку я действительно не хочу, чтобы оно проходило Мое окончательное решение совершенно незамечено (для тех, кто ищет решение).

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 ]

2 голосов
/ 11 июля 2011

Нет необходимости создавать свой собственный ArrayException. Вы можете просто использовать System.AggregateException для переноса нескольких исключений.

1 голос
/ 11 июля 2011

Из вашего кода кажется, что вы должны заключить вызов в цикле в try / catch и поглотить исключение там.

Я не понимаю, как вызывающий OnSave мог бы извлечь выгоду из наличия даже единственного исключения из всех обработчиков событий. Поскольку у вас есть несколько дескрипторов событий, и из вашего архитектурного эскиза кажется, что каждый делает что-то совершенно другое (поскольку каждый должен вызываться), пространство исключений настолько разнородно, что вызывающий не сможет с этим справиться в любом случае.

Таким образом, вопрос может быть: как мне работать с несколькими исключениями событий на более высоком уровне?

Можете ли вы попытаться исправить и повторно запустить OnSave? Придется ли вам пропустить успешные вызовы? И так далее ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...