在"委托、Lambda表达式、事件系列01,委托是什么,委托的基本用法,委托的Method和Target属性"中,反编译委托,发现委托都是多播委托。
既然委托是多播委托,我们可以通过"+="把多个方法赋给委托变量,这样就形成了一个委托链, 它是怎样形成的?来看下面的例子:
monospace; width: 100%; margin: 0em; background-color: #f0f0f0">namespace ConsoleApplication3
{internal delegate void MySayDel(string msg);class Program
{static void Main(string[] args){MySayDel del = SayHello;del = (MySayDel)Delegate.Combine(del, new MySayDel(SayNice)); //等同于:del += SayNice;del += SayOk;del("darren");
}static void SayHello(string msg){Console.WriteLine("hello " + msg);
}static void SayNice(string msg){Console.WriteLine("nice " + msg);
}static void SayOk(string msg){Console.WriteLine("ok " + msg);
}}}
最后,调用委托执行方法,最先注册的方法最先执行。"+="是一种"语法糖",内部其实调用了Delegate的静态方法Combine,形成委托链,再把委托链赋给委托变量。大致如下:
→当执行MySayDel del = SayHello;
→当执行del = (MySayDel)Delegate.Combine(del, new MySayDel(SayNice)),在托管堆上又创建MySayDel委托实例指向SayNice方法,接着复制原先的、指向SayHello方法的委托实例,2个委托实例形成委托链,即蓝色区域部分,栈上的委托变量del指向委托链。
以上,委托的返回类型是void,当调用委托的时候,依次执行委托链的方法。可是,如果委托的返回类型不是void,会不会依次执行委托链的方法呢?
internal delegate int MyCalulateDel(int val1, int val2);class Program
{static void Main(string[] args){MyCalulateDel del = Add;del += Sub;Console.WriteLine(del.Invoke(20, 10));}static int Add(int val1, int val2){return val1 + val2;
}static int Sub(int val1, int val2){return val1 - val2;
}}
以上,当调用委托不会依次执行委托链方法,而是会执行最后注册的方法。
如果我们想得到所有委托方法的返回结果,该如何做到呢?
--委托为我们提供了一个GetInvocationList的实例方法,可以获取所有委托。
internal delegate int MyCalulateDel(int val1, int val2);class Program
{static void Main(string[] args){MyCalulateDel del = Add;del += Sub;var result = GetResultForEachDel(del, 20, 10);foreach (var item in result){Console.WriteLine(item);}}static List<int> GetResultForEachDel(MyCalulateDel del, int val1, int val2){List<int> result = new List<int>();foreach (MyCalulateDel item in del.GetInvocationList()){result.Add(item.Invoke(val1, val2));}return result;
}static int Add(int val1, int val2){return val1 + val2;
}static int Sub(int val1, int val2){return val1 - val2;
}}
以上,通过GetInvocationList实例方法获取所有的委托,然后分别调用所有的委托方法。
总结:
○ 如果委托的返回类型是void,并且形成委托链,只要调用委托就会依次执行委托链方法。
○ 如果委托的返回类型不是void,并且形成委托链,可以使用委托的GetInvocationList实例方法获取所有委托,然后遍历这些委托依次调用委托得到所有返回类型。
“委托、Lambda表达式、事件系列”包括: