Как мне остановить исключения, уничтожающие мою цепочку делегатов? - PullRequest
8 голосов
/ 12 января 2009

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

В Библии ( CLR через C # , я использую C # 2.0) есть короткий параграф об использовании MulticastDelegate.GetInvocationList, чтобы обойти это, но не более того. Итак, мой вопрос: как лучше всего с этим справиться? Должен ли я использовать MulticastDelegate.GetInvocationList каждый раз, когда у меня есть событие? Или мне нужно включить все методы, которые могут быть вызваны как часть цепочки делегатов, в какой-то механизм отката? Почему все эти параметры настолько сложны по сравнению с простой моделью событий / делегатов, которую так легко использовать в C #? И как я могу использовать простой способ, не заканчивая поврежденным состоянием?

Спасибо!

Ответы [ 2 ]

12 голосов
/ 12 января 2009

Если вы просто вызовете делегата, он будет вызывать все целевые методы по порядку. Вам нужно использовать GetInvocationList, если вы хотите выполнить их индивидуально - например:

  • проверять Cancel после каждого
  • для захвата возвращаемого значения каждого
  • для продолжения после отказа отдельной цели

Что касается лучшего способа его использования: как вы хотите, чтобы он вел себя? Мне не понятно ... например, это может вполне подойти для метода расширения:

static void InvokeIgnoreErrors(this EventHandler handler,
        object sender) {
    if(handler != null) {
        foreach(EventHandler subHandler in handler.GetInvocationList()) {
            subHandler(sender, EventArgs.Empty);
        }
    }
}

Тогда вы можете просто позвонить myHandler.InvokeIgnoreErrors(this); (например).

Другим примером может быть:

static bool InvokeCheckCancel(this CancelEventHandler handler,
        object sender) {
    if(handler != null) {
        CancelEventArgs args = new CancelEventArgs(false);
        foreach(CancelEventHandler subHandler in handler.GetInvocationList()) {
            subHandler(sender, args);
            if(args.Cancel) return true;
        }
    }
    return false;
}

, который останавливается после запроса отмены первого события.

1 голос
/ 12 января 2009

Вместо того, чтобы менять способ вызова событий, я думаю, вам следует пересмотреть свои обработчики событий. По моему мнению, методы обработчика событий всегда должны быть написаны так, чтобы они были «безопасными» и никогда не позволяли распространяться исключениям. Это особенно важно, когда вы обрабатываете события в коде графического интерфейса, когда событие вызывается внешним кодом, но это хорошая привычка всегда.

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