在Remoting中客户订阅服务端的事件,如果客户端异常退出,这时在服务端的事件就出错。我的解决办法是逐个调用客户端的处理函数,如果发生异常则中委托链表中删除该函数。由于每个远程事件都要这样的处理,所以我想写一个通用的函数。现在的问题是不能将客户从事件中移除。public static void InvokeDelegate(System.Delegate md,params object[] o)
{
    System.Delegate[]dels=md.GetInvocationList();
    for(int i=0;i<dels.Length;i++)
    {
        try
        {
            dels[i].DynamicInvoke(o);
        }
        catch
        {
            System.MulticastDelegate.RemoveAll(md,dels[i]);
        }
    }
}问题出在函数的签名void InvokeDelegate(System.Delegate md,params object[] o)如果改为下面代码就不会有问题
public static void InvokeDelegate(ref EventHandler md,params object[] o)
{
    System.Delegate[]dels=md.GetInvocationList();
    for(int i=0;i<dels.Length;i++)
    {
        try
        {
            dels[i].DynamicInvoke(o);
        }
        catch
        {
            md-=(System.EventHandler)dels[i];
        }
    }
}如果这样写就必须为每个事件一个这样的函数了....

解决方案 »

  1.   

    //maco_wang跑到技术社区来沙发,真他妈的够恶心
    ===================================================
    一个通用委托,在每个事件绑定就可以了阿如果没有特殊传递参数的话。。
    ===================================================
    技术交流不该有界限 资源共享不该有条件
    博客空间:http://blog.csdn.net/lovingkiss
    资源下载:http://download.csdn.net/user/lovingkiss
    Email:loving-kiss@163.com
    本人说明:<我的帖子我做主,结贴率保持100%>
    1、欢迎一切问题有关的交流——无论答案对错;
    2、不欢迎 顶、Mark、支持之类口水混分的人;
    我保留对非<散分贴>蹭分者的厌恶和鄙视...
    精通:jīnɡtōnɡ对学问技术等透彻的了解并熟练掌握
    所以,我没有精通,只有JZ
    ===================================================
      

  2.   

    MicroSoftor() :我也是这么想的,但是“一般传参”确实不行,不能将委托从事件中删除。
      

  3.   

    LZ看这样稍微改一下可以不?public static void InvokeDelegate(System.Delegate md,params object[] o)
    {
        System.Delegate[]dels=md.GetInvocationList();
        for(int i=0;i<dels.Length;i++)
        {
            try
            {
                dels[i].DynamicInvoke(o);
            }
            catch
            {
                //这样可以不?
               md = System.MulticastDelegate.Remove(md,dels[i]);
            }
        }
    }
      

  4.   

    Event -= EventHandler等同于:System.MulticastDelegate.Remove(Event, EventHandler)
      

  5.   

    你可能不明白Delegate只是一个引用.
    但它就像struct那样,值是固定的.
    你可以把一个Delegate通过组合,分离成另外的Delegate
    但你不能修改它.
    所以,你只能修改引用.你的问题出在ref上.
    因为ref所指定的字段或变量,是必须类型对应的.我给你的建议是把ref改为:public static Delegate Invoke(Delegate list,params object[] args)
    {
        ....
        list=Delegate.Remove(list,detachedClient);
        return list;
    }
      

  6.   

    非常感谢 Lostinet(Hello) 问题解决了!!!还想请教你一个问题,Delegate.Remove 与 Delegate.RemoveAll 有什么区别,微软的解释是Delegate.Remove()----从一个委托的调用列表中移除另一个委托的最后一个调用列表。
    Delegate.RemoveALL()----从一个委托的调用列表中移除另一个委托的所有调用列表。看不太明白,测试也没有发现它们的区别。谁能帮我解释一下?
      

  7.   

    委托的内部维护了一个类似LinkedList的链表(说不准"链表"这个词对不对),比如有一个委托MyDelegate, 它内部是这样的:MyDelegate: MyDelegate1 <-- MyDelegate2 <-- MyDelegate3 <-- MyDelegate4 <-- MyDelegate2 <-- MyDelegate5注意它里边可以把同一个委托包含多次,例如 MyDelegate2 这个实例就包含了两个. 当你做
    Delegate.Remove (MyDelegate, MyDelegate2 ); 的时候,它把最后那一个除去,变成:MyDelegate1 <-- MyDelegate2 <-- MyDelegate3 <-- MyDelegate4 <-- MyDelegate5这就是"移除另一个委托的最后一个调用列表"的意思.至于Delegate.RemoveAll (MyDelegate, MyDelegate2 ); 就把从MyDelegate 中所有的MyDelegate2 都除去,变成:MyDelegate1 <-- MyDelegate3 <-- MyDelegate4 <-- MyDelegate5说到这里,LZ是如果要把发生异常的委托从链表中删除, 还是应该用RemoveAll ,这样一来如果那个异常的委托函数在链表包含多个的时候可以全部删除. 象这样:public static void InvokeDelegate(System.Delegate md,params object[] o)
    {
        System.Delegate[]dels=md.GetInvocationList();
        for(int i=0;i<dels.Length;i++)
        {
            try
            {
                dels[i].DynamicInvoke(o);
            }
            catch
            {
                //从md中全部删除发生异常的dels[i]委托,然后更新md.
               md = System.MulticastDelegate.RemoveAll(md,dels[i]);
            }
        }
    }
      

  8.   

    仔细想一下,实际上每个发生异常的委托(即使是多个相同的实例,比如MyDelegate2)都有机会被Catch到,也不需要用RemoveAll,所以我LS的和我最当初说的是一样效果:public static void InvokeDelegate(System.Delegate md,params object[] o)
    {
        System.Delegate[]dels=md.GetInvocationList();
        for(int i=0;i<dels.Length;i++)
        {
            try
            {
                dels[i].DynamicInvoke(o);
            }
            catch
            {
                //从md中删除发生异常的dels[i]委托
               md = System.MulticastDelegate.Remove(md,dels[i]);
            }
        }
    }
      

  9.   

    感谢 RedGoldFish(红金鱼) ,解释非常详细。
    不过需要注意的是 md = System.MulticastDelegate.Remove(md,dels[i]);确实不能带回新的委托链表,这一点已经才程序中得到证实。用ref也不行,正如 Lostinet(Hello)所说“ref所指定的字段或变量,是必须类型对应的”我的解决方法是
    public static Delegate InvokeDelegate(Delegate md,params object[] o)