可以认为委托是持有一个或多个方法的对象,但委托与对象不同,可以执行委托,这时委托会执行它所持有的方法。 如果学过C/C++可以将委托理解成函数指针的升级版。
初识委托 委托与类平级,所以一般声明在类声明的位置,委托的访问性默认是internal。
1 2 3 4 5 6 7 8 9 10 internal class Program {     static void Main(string[] args) {         MyDel del = new MyDel(SayHello);         del.Invoke();     }     static void SayHello() {         Console.WriteLine("Hello world!");     } } delegate int MyDel(int i); 
 
创建委托实例时,可以传入实例方法或者静态方法的方法名。
初始化委托 我们已经见到了new的赋值方法
1 MyDel del = new MyDel(Ix10); 
 
也可以使用委托赋值的快捷方法
 
组合委托 委托可以使用额外的运算符来组合。这个运算最终会创建一个新的委托,其调用列表连接了作为操作数的两个委托的调用列表副本。
1 2 3 MyDel del1 = SayHello; MyDel del2 = Human.Eat; MyDel del3 = del1+del2; 
 
多播委托 我们已经展示过了组合委托,通过+运算符可以将两个委托组合起来,+和+=运算符还可以给委托增加方法到委托的调用队列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 internal class Program {     static void Main(string[] args) {         MyDel del = SayHello;         del += Human.Eat;         del = del +SayHello;         del();     }     static void SayHello() {         Console.WriteLine("hello world");     } } delegate void MyDel(); public class Human {     public static void Eat() {         Console.WriteLine("我可以吃饭");     } } 
 
在使用+=运算符时,实际上发生的是创建了一个新的委托,其调用列表是左边的委托加上右边方法的组合,然后将这个委托赋值给del。 由代码的执行结果来看,其调用顺序与添加方法的顺序相同。
移除委托方法 可以使用-和-=运算符从委托移除方法 。 如果在调用列表中的方法有多个实例,-=运算符将从列表最后开始搜索,并且移除第一个与方法匹配的实例。 试图删除委托中不存在的方法将无效。 试图调用空委托会抛出异常,可以通过将委托和null进行比较来判断委托的调用列表是否为空。如果为空则委托是null。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 internal class Program {     static async Task Main(string[] args) {         Action action = SayHello;         action += Human.Eat;         action = action + SayHello;         action = action - SayHello;         action -= Human.Eat;         action();     }     static void SayHello() {         Console.WriteLine("hello world");     } } delegate void MyDel(); public class Human {     public static void Eat() {         Console.WriteLine("我可以吃饭");     } } 
 
显式异步调用多播委托 多播委托默认是同步调用的,但我们可以使用Thread或Task显式异步调用。 Thread:
1 2 3 4 5 //using System.Threading; MyDel del = SayHello; del += Human.Eat; Thread thread = new Thread(new ThreadStart(del));//可以直接传入方法名或委托实例 thread.Start(); 
 
Task:
1 2 3 4 5 6 7 static async Task Main(string[] args) {       Action action = SayHello;       action += Human.Eat;       Task task = new Task(action);       task.Start();       await Task.Delay(1000); } 
 
异步调用看不懂没关系,我会在异步编程中介绍的。Task之所以加了Delay是因为如果不await,代码会在执行Human.Eat或者SayHello之前退出。
Action<>委托 Action委托无需自己定义,由C#语言定义只需要使用即可。 Action委托是泛型委托用于无返回值的函数,泛型列表中是被委托函数的参数列表。
1 2 3 4 5 6 7 8 9 internal class Program {     static void Main(string[] args) {         Action<string> action = Say;         action("你好世界");     }     static void Say(string str) {         Console.WriteLine(str);     } } 
 
Func<>委托 Func<>委托无需自己定义,由C#语言定义只需要使用即可。 Func<>委托是泛型委托用于有返回值的函数,泛型列表中最后一个是方法返回值类型,前几个是被委托函数的参数类型。
1 2 3 4 5 6 7 8 9 10 internal class Program {         static void Main(string[] args) {             Func<int, int, int> func = new Func<int, int, int>(add);             int res = func(3,4);             Console.WriteLine(res);         }         static int add(int a,int b) {             return a + b;         }     }