C# 用委托有什么好处? 它起什么作用?
什么是委托
首先要知道什么是委托,用最通俗易懂的话来讲,你就可以把委托看成是用来执行方法(函数)的一个东西。
(1) 从数据结构来讲,委托是和类一样是一种用户自定义类型。
(2) 从设计模式来讲,委托(类)提供了方法(对象)的抽象。
既然委托是一种类型,那么它存储的是什么数据?
我们知道,委托是方法的抽象,它存储的就是一系列具有相同签名和返回回类型的方法的地址。调用委托的时候,委托包含的所有方法将被执行。
如何使用委托
在使用委托的时候,你可以像对待一个类一样对待它。即先声明,再实例化。只是有点不同,类在实例化之后叫对象或实例,但委托在实例化后仍叫委托。如下:
1 namespace Vczx.ProCSharp.Exc 2 { 3 delegate double MathsOp( double x ); 4 //class defination here 5 }
这就声明了一个委托
意义:任何一个返回值为double,且只有一个形参为double的函数,都可以用这个委托来调用。
注意:
-
需求情况而定,一般定义在与类定义平级部分,且用public修饰,便于外部的调用。
-
若定义于类的内部,则必须通过调用该类的成员才能取得其委托的引用,在频繁的调用该委托的情况下,就不是很适合。
实例化:
首先我们要先有一个满足委托声明的方法,假设一个返回一个数的2倍的方法:
1class MathsOperations 2{ 3 public static double MultiplyBy2( double value ) 4 { 5 return value * 2; 6 } 7}
有了这样一个方法,我们就可以实例化一个委托了:
MathsOp operation = new MathsOp( MathsOperations.MultiplyBy2 );
在实例化一个委托时,要给它一个参数,这个参数就是委托执行的方法,它可以是静态方法,也可以是实例方法(这一点有别于函数指针,函数指针只能调用静态方法),如:
MathsOp operation = new MathsOp( new Class1().Method1 );
在实例化完一个委托之后,就可以用这个委托来调用方法了:
double result = operation( 1.23 );
例子代码:
1 namespace Vczx.ProCSharp.Exc 2 { 3 delegate double MathsOp( double x ); 4 class Start 5 { 6 public class MyDelegate 7 { 8 public static double MultiplyBy2( double x ) 9 { 10 return x * 2; 11 } 12 } 13 [STAThread] 14 static void Main(string[] args) 15 { 16 MathsOp operation = new MathsOp( MyDelegate.MultiplyBy2 ); 17 double x = 1.23; 18 double result = operation( x ); 19 Console.WriteLine( “{0} multiply by 2 is {1}”, x, result ); 20 Console.Read(); 21 } 22 } 23 }
多路广播委托
前面使用的委托只包含一个方法调用。调用委托的次数与调用方法的次数相同。如果要调用多个方法,就需要多次显示调用这个委托。其实委托也可以包含多个方法,这种委托就是多路广播委托。多路广播委托派生于System.MulticastDelegate,它的Combine方法允许把多个方法调用链接在一起,我们可以通过+=来向委托添加调用方法,也可以用-=删除其中的调用方法。如:
1 namespace Vczx.ProCSharp.Exc 2 { 3 public class MyDelegate 4 { 5 public static void MultiplyBy2( double value ) 6 { 7 double result = value * 2; 8 Console.WriteLine( “Multiplying by 2: {0} gives {1}”, value, result ); 9 } 10 11 public static void Squre( double value ) 12 { 13 double result = value * value; 14 Console.WriteLine( “Squaring: {0} gives {1}”, value, result ); 15 } 16 } 17 18 delegate void MathsOp( double x ); 19 20 class Start 21 { 22 [STAThread] 23 static void Main(string[] args) 24 { 25 MathsOp operation = new MathsOp( MyDelegate.MultiplyBy2 ); 26 operation += new MathsOp( MyDelegate.Squre ); 27 double x = 1.23; 28 operation( x ); 29 30 operation -= new MathsOp( MyDelegate.MultiplyBy2 ); 31 operation( x ); 32 33 Console.Read(); 34 } 35 } 36 }
输出:
Multiplying by 2: 1.23 gives 2.46
Squaring: 1.23 gives 1.5129
Squaring: 1.23 gives 1.5129
注意,多路广播委托声明时必须返回void,否则返回值不知道应该送回什么地方。对此,我做了一个测试:如果不将委托的声明返回void,则返回值返回的是最后一个链入委托链的方法的返回值,编译不会出错。
为什么要用委托
使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时知道将调用哪个方法。与C或C++中的函数指针不同,委托是面向对象,而且是类型安全的
补充
委托调用跟方法调用类似。委托调用后,调用列表的每个方法将会被执行。
在调用委托前,应判断委托是否为空。调用空委托会抛出异常。
if(null != del) { del();//委托调用 }
匿名方法
匿名方法是在初始化委托时内联声明的方法。
基本结构:
deleage( 参数 ) { 语句块 }
例如:
delegate int MyDel (int x); //定义一个委托
MyDel del = delegate( int x){ return x; };
从上面我们可以看到,匿名方法是不会显示声明返回值的。
Lambda表达式
Lambda表达式主要用来简化匿名方法的语法。在匿名方法中,delegate关键字有点多余,因为编译器已经知道我们将方法赋值给委托。通过几个简单步骤,我们就可以将匿名方法转换为Lambda表达式:
- 删除delegate关键字
- 在参数列表和匿名方法主体之间防Lambda运算符=>。Lambda运算符读作"goes to"。
MyDel del = delegate( int x) { return x; };//匿名方法 MyDel del2 = (int x) => {return x;};//Lambda表达式 MyDel del3 = x => {return x};//简写的Lambda表达式
Action和Func
1.Action说明
Action是.NET Framework内置的泛型委托,可以使用Action委托以参数形式传递方法,而不用显示声明自定义的委托。封装的方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有一个通过值传递给它的参数,并且不能有返回值。
2.Action 的特点
3.例子
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class ActionDemo : MonoBehaviour { Action action;//表示无参 Action<int> action1;//表示有传入参数int void Start() { action = actionH1;//没有参数 action(); action1 = actionH2;//一个 int参数 action1(456); actionH3(() => { Debug.Log("执行完actionH3了"); });//lambda 表达式 来执行委托 actionH3(actionH4);//执行完 actionH3后回调 actionH4方法 } private void actionH1()//没有参数 { Debug.Log(123); } private void actionH2(int index)//参数int { Debug.Log(index); } private void actionH3(Action act)//参数 Action { Debug.Log("在执行actionH3"); act();//回调 这个 委托方法 } private void actionH4()//执行完 actionH3后的回调执行 { Debug.Log("执行完actionH3了"); } }
delegate 和 Action 写法对比
delegate 写法
public delegate void CommonDelegate(string str);//定义委托 void Start() { CommonDelegate common = Init;//实例化委托 common("hello world");//执行 } private void Init(string str)//放发 { Debug.Log(str);//打印 }
修改为Action 写法
void Start() { Action<string> act = Init; act("hello world"); } private void Init(string str)//放发 { Debug.Log(str);//打印 }
Action 代码更简洁点
Func
Func和Action相同点 :
Func的返回值
Func< T1 > (有返回值)------无参数类型,T1为返回值类型
Func<T1,T2>(有返回值)------T1为0-16个参数类型,T2为返回值类型
Func<T1,T2,T3>(有返回值)------T1和T2为0-16个参数类型,T3为返回值类型
也就是说 参数最后一位就是返回值类型(返回值的类型和Func输出参数类型相同)
Func<int【参数类型】,……,bool【最后一个是返回值类型】】> func
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class FuncDemo : MonoBehaviour { /* Func<参数.....> //参数最后一位就是 委托的 返回类型 */ void Start() { Func<string> MyFun1 = MyMethodA;//这样定义 就是 无参的Func 返回一个string Debug.Log(MyFun1());//执行 这个委托 Func<string,string> MyFun2 = MyMethodB;//这样定义 就是参数为string的Func 返回一个string值 Debug.Log(MyFun2("一个参数"));//执行 这个委托 //一次类推 Func<string, string,bool> MyFun3 = MyMethodC;//这样定义 就是2个参数为string的Func 返回一个bool值 Debug.Log(MyFun3("一个参数","二个参数"));//执行 这个委托 } //无参 返回string private string MyMethodA() { return "MyMethodA--> hello world"; } //一个string参数 +返回值string值 private string MyMethodB(string arg) { return "MyMethodB--> hello world " + arg; } //两个string参数 +返回bool值 private bool MyMethodC(string arg1, string arg2) { Debug.Log("MyMethodC--> hello world " + arg1 + " " + arg2); return true; } }
运行结果
简单的来说
有返回值就用Func,无返回值就用Action
原文链接:https://blog.csdn.net/qq_39984000/article/details/115245134
原文:https://www.cnblogs.com/asdyzh/p/9846206.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人