首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MulticastDelegate和异常处理:有没有可能把它们都包装起来?

MulticastDelegate和异常处理:有没有可能把它们都包装起来?
EN

Stack Overflow用户
提问于 2010-11-12 06:45:54
回答 3查看 1K关注 0票数 3

在调用多播代理时,应该使用GetInvocationList逐个调用代理:

代码语言:javascript
复制
public void IterateAll()
{
    if( _doExecute != null )
    {
        foreach( ExecuteCallback doSingleExecute in _doExecute.GetInvocationList() )
        {
            try
            {
                doSingleExecute();
            }
            catch
            {
                // This delegate threw an exception
            }
        }
    }
}

有没有一种方法可以泛化这一点,通过包装这个迭代来返回到一个单一的调用,从而隐藏它,并且使得一个人可以再次调用整个多播委托?这将更接近意向水平。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-11-12 06:59:21

你可以这样做:

代码语言:javascript
复制
public static void CallAllAndCatch(this Action self)
{
    if (self == null)
        return;

    foreach (Action i in self.GetInvocationList()) {
        try { i(); }
        catch { }
    }
}

请注意,如果你发现自己经常使用EventHandler<T>来做这件事,你可以使用泛型,但是你不能对任何类型的委托通用地这样做,因为委托类型不能在彼此之间分配,即使它们是兼容的,并且在定义泛型方法时没有机制来限制特定的泛型参数成为具有特定签名的委托。(我认为从.NET 4开始,具有相同签名的委托被认为是兼容的类型。)

对于EventHandler<T>方法:

代码语言:javascript
复制
public static void CallAllAndCatch(this EventHandler<T> self, object sender, T args)
    where T : EventArgs
{
    if (self == null)
        return;

    foreach (EventHandler<T> i in self.GetInvocationList()) {
        try { i(sender, args); }
        catch { }
    }
}

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

代码语言:javascript
复制
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.
    }
}
票数 6
EN

Stack Overflow用户

发布于 2010-11-12 07:34:57

Hmya,这很可疑。只有当您能够恢复程序的状态时,捕获异常并处理它才能真正起作用,这样看起来就像从未发生过异常一样。对于MulticastDelegate来说,这是完全不可能的。

它的约定是你不知道什么样的代码为它订阅了一个事件处理程序。如果完全未知代码抛出异常且不处理自身,那么您根本无法猜测如何恢复状态。事件处理程序可能已经完成了一系列工作,改变了状态,然后在接近尾声的地方死了。你没有希望取消“一堆工作”的部分,代码对你来说是未知的。它可能是在您编写代码的几个月或几年后编写的。

真不是个好主意,不要这样做。

票数 2
EN

Stack Overflow用户

发布于 2010-11-12 07:03:17

委托的类型是固定的吗?你要么需要使用相当多的反射,要么需要为每个可能的参数计数实现一个版本,就像它有一个Action<...>类型一样。

应该看起来像这样(未测试的记事本代码):

代码语言:javascript
复制
  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);
  }

而且您可能需要为单类型转换委托添加特殊的情况处理。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4160031

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档