c#中的委托(二)
1.委托链
委托链是委托对象的集合,利用委托链调用集合中的委托所绑定的全部方法。委托对象可使用 "+" 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。"-" 运算符可用于从合并的委托中移除组件委托。
2.简单示例
using System; namespace 委托4 { //计算类 public class Compute { ///加法 public static void add(double a,double b) { Console.WriteLine("两数相加的和为{0}", a + b); } //乘法 public static void mul(double a, double b) { Console.WriteLine("两数相乘的积为{0}", a * b); } } class Program { // 声明一个委托 public delegate void result(double c,double d); static void Main(string[] args) { result r1 = new result(Compute.add); result r2 = new result(Compute.mul); r1 += r2;//向委托增加一个方法 //委托具体调用方法,给定实参列表,先调用Compute.add,再调用Compute.mul r1(5.0,6.0); Console.ReadKey(); } } }
运行结果:
一个合并委托调用它所合并的两个委托,只有相同类型的委托可被合并。C#编译器重载了+=和-=操作符,这两个操作符分别调用Combine和Remove方法。
3.委托的简化(以下内容转自https://www.cnblogs.com/jixiaosa/p/10687068.html)
3.1示例
using System; namespace 委托5 { // 声明一个委托 public delegate void result(int c, int d); //计算类 public class Compute { ///加法 public static void add(int a, int b) { Console.WriteLine("两数相加的和为{0}", a + b); } //乘法 public static void mul(int a, int b) { Console.WriteLine("两数相乘的积为{0}", a * b); } } class Program { /// <summary> /// Test函数,输出b-a次result方法调用 /// </summary> /// <param name="a">开始</param> /// <param name="b">结束</param> /// <param name="r">委托引用</param> private static void Test(int a, int b,result r) { for(int i=a; i<b; i++) { r(a, b); } } static void Main(string[] args) { //创建result委托对象,并指定方法 result r1 = Compute.add; Test(1, 3,r1); //创建result委托对象,并指定方法 Test(1, 3, new result(Compute.mul)); Console.WriteLine("************************"); //简化1,不用创建result委托对象 Test(1, 3, Compute.add); //简化2,不用指定委托的方法 Test(1, 3, (a, b)=>{ Console.WriteLine("两数相乘的积为{0}", a * b); }); Console.ReadKey(); } } }
3.2不用创建委托变量
//创建result委托对象,并指定方法 result r1 = Compute.add; Test(1, 3,r1); //创建result委托对象,并指定方法 Test(1, 3, new result(Compute.mul)); Console.WriteLine("************************"); //简化1,不用创建result委托对象,直接写方法名称 Test(1, 3, Compute.add);
代码更简洁,可读性更强。
3.3不用指定委托引用的方法
使用lambda表达式定义一个匿名函数,编译器在看到lambda表达式之后会在类中自动定义一个新的私有方法。类似于之前写的回调方法Compute.add,lambda必须匹配委托!
//创建result委托对象,并指定方法 result r1 = Compute.add; Test(1, 3,r1); //创建result委托对象,并指定方法 Test(1, 3, new result(Compute.mul)); Console.WriteLine("************************"); //简化1,不用创建result委托对象 Test(1, 3, Compute.add); //简化2,不用指定委托的方法 Test(1, 3, (a, b)=>{ Console.WriteLine("两数相乘的积为{0}", a * b); });
lambda的语法: 参数 => 方法体。
=>左边是要传入的参数,本例中是传入一个Int类型的变量,=>右边是具体的代码,相当于Compute.add{}中所做的操作
一些规则:
如果不传递参数: ()=>Console.WriteLine("Hello World!")
传递一个参数:(int n)=>Console.WriteLine(n.ToString()) 或者去掉()和int 编译器会自己推断类型:n=>Console.WriteLine(n.ToString())
传递多个参数:(int n ,int m)=>Console.WriteLine(n.ToString()) 或者编译器自己推断类型:(n , m)=>Console.WriteLine(n.ToString())
注:如果有一个方法需要多处调用或者方法里面的代码量较多。还是单独写一个方法较为理想。
运行结果:
匿名委托虽然减少了一点代码,但还是要求我们自己去声明委托。是否还能再简写一点?
4.C#内置委托(转自https://www.cnblogs.com/dotnet261010/p/10108791.html)
4.1Action委托(无返回值)
(1)定义
Action<T>是.NET Framework内置的泛型委托,可以使用Action<T>委托以参数形式传递方法,而不用显示声明自定义的委托。封装的方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有一个通过值传递给它的参数,并且不能有返回值。
(2)示例(转自:https://www.cnblogs.com/winformasp/articles/12033397.html)
Action 表示无参,无返回值的委托。
Action<int,string> 表示有传入参数int,string无返回值的委托。
Action<int,string,bool> 表示有传入参数int,string,bool无返回值的委托。
Action<int,int,int,int> 表示有传入4个int型参数,无返回值的委托。
using System; namespace action委托 { class Program { static void Main(string[] args) { //定义Action委托,无参数,无返回值 Action act01; //使用Lambda表达式添加方法语句块 act01 = () => Console.WriteLine("我是Action无参数的委托"); //调用 act01(); //定义Action委托,有1个参数,无返回值 Action<int> act02; act02 = (int a) => Console.WriteLine("我是Action有1个参数的委托{0}", a); act02(666); //定义Action委托,有2个参数,无返回值 Action<int, string> act03; act03 = (int a, string str) => { Console.WriteLine("我是Action有2个参数的委托,第一个参数是{0},第二个是{1}", a, str); }; act03(666, "sixsixsix"); Console.ReadKey(); } } }
运行结果:
4.2Func委托(有返回值)
(1) Func委托代表有返回类型的委托
(2)示例(转自:https://www.cnblogs.com/winformasp/articles/12033397.html)
Func至少0个输入参数,至多16个输入参数,根据返回值泛型返回。必须有返回值,不可void。
Func<int> 表示没有输入参数,返回值为int类型的委托。
Func<object,string,int> 表示传入参数为object, string ,返回值为int类型的委托。
Func<object,string,int> 表示传入参数为object, string, 返回值为int类型的委托。
Func<T1,T2,,T3,int> 表示传入参数为T1,T2,,T3(泛型),返回值为int类型的委托。
using System; namespace action委托 { class Program { static void Main(string[] args) { //定义Func委托,没有参数,返回值是int Func<int> func01; func01 = () => { Console.Write("一个无参数的Func委托,返回值是:"); return 666; }; Console.WriteLine(func01()); //定义Func委托,有两个string参数,返回值是int,注意返回值是在<>的最后一个 Func<string, string, int> func02; func02 = (string str01, string str02) => { Console.Write("{0}一个有两个string类型参数的Func委托{1},返回值是int类型:", str01, str02); return 666; }; var Temp = func02("我是", "类型"); Console.WriteLine(Temp); Console.ReadKey(); } } }
运行结果:
4.3 Action与Func的异同
(1)Action<T>只有参数列表,没有返回值;Func<Result>有返回类型。
(2)Func<Result>与Action<T>都支持Lambda表达式。
(2)Func<Result>与Action<T>都支持0~16个参数。
参考文章:
https://docs.microsoft.com/zh-cn/dotnet/csharp/delegate-class
https://blog.csdn.net/lizhenxiqnmlgb/article/details/82141968
https://www.cnblogs.com/kiba/p/9330936.html
https://www.runoob.com/csharp/csharp-delegate.html
https://www.cnblogs.com/jixiaosa/p/10687068.html
https://www.cnblogs.com/dotnet261010/p/10108791.html