可以认为委托是持有一个或多个方法的对象,但委托与对象不同,可以执行委托,这时委托会执行它所持有的方法。 如果学过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; } }