日期:2014-05-19  浏览次数:21006 次

怎样删除事件委托链表中的某个委托
在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];
                }
        }
}

如果这样写就必须为每个事件一个这样的函数了....



------解决方案--------------------
你可能不明白Delegate只是一个引用.
但它就像struct那样,值是固定的.
你可以把一个Delegate通过组合,分离成另外的Delegate
但你不能修改它.
所以,你只能修改引用.

你的问题出在ref上.
因为ref所指定的字段或变量,是必须类型对应的.

我给你的建议是把ref改为:

public static Delegate Invoke(Delegate list,params object[] args)
{
....
list=Delegate.Remove(list,detachedClient);
return list;
}
------解决方案--------------------
委托的内部维护了一个类似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.Deleg