MulticastDelegate和Exception处理:是否可以将它全部包装起来?

在调用多播委托时,应该使用GetInvocationList逐个调用委托:

public void IterateAll() { if( _doExecute != null ) { foreach( ExecuteCallback doSingleExecute in _doExecute.GetInvocationList() ) { try { doSingleExecute(); } catch { // This delegate threw an exception } } } } 

是否有一种方法可以对此进行泛化,以便通过包装此迭代来回到单个调用以隐藏它,以便可以再次调用整个多播委托? 这将更接近故意水平。

你可以这样做:

 public static void CallAllAndCatch(this Action self) { if (self == null) return; foreach (Action i in self.GetInvocationList()) { try { i(); } catch { } } } 

请注意,如果您发现自己使用例如EventHandler进行了很多操作,则可以使用generics,但是对于任何类型的任何委托都不能执行此操作,因为委托类型之间不能分配,即使它们是兼容的,并且在定义将特定generics参数限制为具有特定签名的委托的generics方法时,没有任何机制。 (我认为具有相同签名的代理被认为是以.NET 4开头的兼容类型。)

对于EventHandler方法:

 public static void CallAllAndCatch(this EventHandler self, object sender, T args) where T : EventArgs { if (self == null) return; foreach (EventHandler i in self.GetInvocationList()) { try { i(sender, args); } catch { } } } 

如果你不介意抛出性能和编译时类型检查管,你可以这样做,这将适用于任何委托类型:

 public static void CallAllAndCatch(this Delegate self, params object[] args) where T : EventArgs { if (self == null) return; foreach (Delegate i in self.GetInvocationList()) { try { i.DynamicInvoke(args); } catch (MemberAccessException) { throw; } // A type of something in args isn't compatible with the delegate signature. catch (TargetException) { throw; } // The delegate itself is invalid. catch { } // Catch everything else. } } 

Hmya,这很可疑。 捕获exception并处理它只能在恢复程序状态时才能正常工作,以便看起来exception从未发生过。 对于MulticastDelegate来说,这是完全不可能的。

它的合同是你不知道哪种代码为它订阅了一个事件处理程序。 如果那个完全未知的代码抛出exception并且没有自己处理,那么你完全没有想到如何恢复状态。 事件处理程序可能已经做了很多工作,变异状态,然后在接近结束时死亡。 你没有希望不做“工作”部分,你不知道这些代码。 它可能是在您编写代码后的几个月或几年内编写的。

真的不好主意,不要这样做。

委托的类型是否已修复? 您需要使用相当多的reflection,或者您需要为每个可能的parametercount实现一个版本,就像它有一个Action <...>类型一样。

看起来应该与此类似(未经测试的记事本代码):

  public static Action WrapAction(Action a) { var invList = ((MultiCastDelegate)a).GetInvocationList(); for (int i = 0; i < invList.Length; i++) { invList[i] = ()=>{try invList[i] catch {...} }); } return (Action)MulticastDelegate.Combine(invList); } 

您可能需要为单个演员代表添加特殊案例处理。