8

我遇到了一个常见的问题。当我有一个事件可能被几个不同的类订阅时,这些类之一抛出的异常将终止回调链;因为我不知道执行回调的先验顺序,这可能会导致某些类的不可预测的状态更改,而不是其他类。

在圣经中(通过 C# 的 CLR,我使用的是 C# 2.0)有一小段关于使用MulticastDelegate.GetInvocationList来解决这个问题,但仅此而已。所以我的问题是:处理这个问题的最佳方法是什么?我MulticastDelegate.GetInvocationList每次有活动都必须使用吗?或者我是否需要将所有可能作为委托链的一部分调用的方法包含在某种回滚机制中?与在 C# 中如此易于使用的简单事件/委托模型相比,为什么所有这些选项都如此复杂?我怎样才能使用简单的方法而不会导致损坏状态?

谢谢!

4

2 回答 2

12

如果您只是调用一个委托,它将按顺序调用所有目标方法。如果您想单独执行它们,则需要使用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;
}

在第一个事件请求取消后停止。

于 2009-01-12T09:19:14.793 回答
1

我认为您应该查看事件处理程序,而不是更改调用事件的方式。在我看来,应该始终编写事件处理程序方法,以便它们是“安全的”并且永远不会让异常传播。当您在 GUI 代码中处理由外部代码调用事件的事件时,这一点尤其重要,但始终是一个好习惯。

于 2009-01-12T11:12:43.707 回答