今天改bug碰到了一个问题,有多个方法注册到了一个事件里去,而这些方法本身又有点儿互斥,因而造成了bug,哥调试半天才发现,郁闷至极,遂复习了以前的知识并进行适当延伸,再将成果记录及分享之,以防他日再犯。
显然这是一个委托链,那么首先就来回顾下委托链的最初写法了,这里引用上一篇 委托的N种写法,你喜欢哪种? 的部分代码。
定义委托:
delegate string PlusStringHandle(string x, string y);
定义对应的方法:
static string plusString(string x, string y) { Console.WriteLine("plusString方法被调用......"); return x + y; }
调用:
PlusStringHandle handle = null; handle += plusString; handle += plusString; string str = handle("aa", "bb"); Console.WriteLine("调用委托获取返回值:{0}", str); Console.WriteLine("委托注册的默认方法名:{0}", handle.Method.Name);
结果:
再定义一个方法:
static string testString(string x, string y) { Console.WriteLine("testString方法被调用......."); return x + x + y + y; }
使用-=:
PlusStringHandle handle = null; handle += plusString; handle += plusString; handle += testString; handle -= plusString; handle -= testString; string str = handle("aa", "bb"); Console.WriteLine("调用委托获取返回值:{0}", str); Console.WriteLine("委托注册的默认方法名:{0}", handle.Method.Name);
运行发现仍然调用了 plusString 方法,这就是产生文中开头所说的bug的原因了。
继续修改Main方法:
PlusStringHandle handle = null; handle += plusString; handle += plusString; handle += testString; //handle -= plusString; //handle -= testString; handle = testString; //或者先将handle置为null再使用+= string str = handle("aa", "bb"); Console.WriteLine("调用委托获取返回值:{0}", str); Console.WriteLine("委托注册的默认方法名:{0}", handle.Method.Name);
这就是我要的结果,让委托不再受以前注册过的方法影响。
=======================分割线 =============================
以下继续来探讨下委托链获取的返回值,如上文所写,直接调用委托只能获取最后一次注册的方法的返回值,那么假如说要获取所有已注册的方法的返回值则有两种方式:
PlusStringHandle handle = null; handle += plusString; handle += plusString; handle += testString; string str = handle("aa", "bb"); Console.WriteLine("调用委托获取返回值:{0}", str); Console.WriteLine("委托注册的默认方法名:{0}", handle.Method.Name); Delegate[] delegates = handle.GetInvocationList(); Console.WriteLine("以下遍历获取委托链中的返回值=============================================="); foreach (PlusStringHandle d in delegates) { Console.WriteLine("调用的方法:{0},获取方法返回值:{1}", d.Method.Name, d("qq", "ww")); } foreach (Delegate d in delegates) { //d即为PlusStringHandle类型 Console.WriteLine("调用的方法:{0},获取方法返回值:{1}", d.Method.Name, d.DynamicInvoke("qq", "ww")); }
说是两种方式,其实异曲同工,不同的写法,其中一种是动态调用而已了。