C#学习笔记 -- 委托
委托
1、什么是委托
委托是持有一个或多个方法的对象, 委托与典型的对象不同, 可以执行委托, 这时候委托会执行它所持有的方法
2、概述
委托和类一样是一种用户定义类型, 但类表示的是数据和方法的集合, 而委托则持有一个或多个方法, 以及一系列预定义操作
可以把delegate看作一个包含有序方法列表的对象, 这些方法具有相同的签名和返回类型
-
方法的列表称为调用列表
-
委托持有的方法可以来自任何类或结构, 只要他们在如下方面匹配
-
委托的返回类型
-
委托的签名(包括ref和out修饰符)
-
-
调用列表中的方法可以是实例方法也可以是静态方法
-
在调用委托的时候, 会执行其调用列表所有方法
使用委托的步骤
-
声明一个委托类型. 声明委托与方法声明相似, 只是没有实现块
delegate void MyDel(int val); -
使用该委托类型声明一个委托变量
MyDel del; -
创建一个委托类型的对象, 并把它赋值给委托变量. 新的委托对象包含指向某个方法的引用, 这个方法的签名和返回类型必须跟第一步中定义的委托类型一样
public class Printer { public void Print(int val) { Console.WriteLine($"val = {val}"); } } Printer printer = new Printer(); int val = 1; del = new MyDel{ printer.Print(val) }; -
可以选择为委托对象添加其他方法, 这些方法的签名和返回类型必须与第一步中定义的委托类型相同
-
可以像调用方法引用调用委托, 在调用委托的时候, 其包含的每个方法都会被执行
比较类和委托
类 | 委托 | |
---|---|---|
声明类型 | 声明类 | 声明委托 |
声明类型的变量 | 声明类类型的变量 | 声明委托类型的变量 |
填充变量 | 创建类的实例并且把它的引用赋值给类型 | 创建委托的实例并且把它的引用赋值给变量, 然后增加第一个方法 |
使用变量 | 使用类对象 | 调用委托对象 |
3、声明委托
委托是类型, 返回类型和签名指定了委托接受的方法的形式
delegate 返回类型 委托类型名称(int x); delegate void MyDel(int x);
注意 : 委托类型声明与方法不同如下
-
以delegate关键字开头
-
无方法主体
-
委托类型声明不需要在类内部声明, 因为他是类型声明
4、创建委托
有两种创建方式, 一种是使用new
-
括号其中包含作为调用列表中第一个成员的方法的名称, 该方法可以是实例方法或静态方法
//实例方法 MyDel delVar = new MyDel(myInstObj.MyM1); //静态方法 MyDel dVar = new MyDel(SClass.OtherM2);
一种是快捷语法, 仅由方法说明符构成
-
这种语法是因为方法名称和其他相应的委托类型之间存在隐式转换
//实例方法 MyDel delVar = myInstObj.MyM1; //静态方法 MyDel dVar = SClass.OtherM2;
除了为委托分配内存, 创建委托对象还会把第一个方法放入委托的调用列表
5、给委托赋值
由于委托是引用类型, 我们可以通过给他赋值来改变包括在委托变量中的引用, 旧的委托对象会被垃圾回收站回收
MyDel delVar = myIstObjc.MyM1; MyDel delVar = SClass.OtherM2;
6、组合委托
MyDel delA = myIstObjc.MyM1; MyDel delB = SClass.OtherM2; MyDel delC = delA + delB;
-
组合委托实际上并没有修改
-
委托是恒定的, 委托对象被创建后不能再被改变
7、为委托添加方法
-
使用
+=
符号添加方法 -
在委托的调用列表“添加”了两个方法, 加在列表底部
-
看上去可以为委托添加, 实际上是新建了一个委托, 委托指定组合, 再把新委托赋值给旧委托
-
每次给委托添加方法, 都会在调用列表中新创建一个元素
MyDel delVar = myIst.MyM1; delVar += SCl.M3; delVar += X.Act;
8、为委托移除方法
-
使用
-=
符号移除方法 -
与委托添加方法一致
-
如果调用列表中的方法有多个实例,
-=
符号从列表最后开始搜索, 并移除第一个与方法匹配的实例 -
试图删除委托中不存在的方法将无效
-
对空委托使用移除方法会出现异常, 可以通过将委托和null比较, 来判断为委托的调用列表是否为空,
9、调用委托
-
在调用委托时, 他使用相同的参数来执行调用列表中的每一个方法
-
可以通过两种方式调用委托, 一种像是调用方法一样调用委托, 另一种是使用委托的
Invoke()
-
如下方代码块, 可以将参数放在调用的圆括号内, 用于调用委托的参数作用与调用列表中的每一个方法(除非一个参数是输出参数)
int val = 55; delVar(val); -
如果一个方法在调用列表中多次出现, 则在调用委托时, 每次在列表中遇到该方法时都会调用他
-
调用时委托不能为空, 否则将引发异常, 可以使用if语句进行检查, 也可以使用空条件运算符和
Invoke()
int val = 55; if(delVar != null) { delVar(val); } //等价 delVar?.Invoke(val);
10、调用空返回类型的委托
public delegate void PrintFunction();
class Printer { public void Print1() { Console.WriteLine("Print1 -- instance"); } public static void Print2() { Console.WriteLine("Pinter2 -- static"); } }
static void Main(string[] args) { Printer printer = new Printer(); //初始化委托 PrintFunction pfDelegate = printer.Print1; //添加委托 pfDelegate += Printer.Print2; pfDelegate += printer.Print1; pfDelegate += Printer.Print2; //执行委托 //空条件运算符检查委托内是否为空 pfDelegate?.Invoke(); //使用if判断 if (pfDelegate != null) { pfDelegate(); } else { Console.WriteLine("empty"); } }
11、调用带返回值的委托
如果委托有返回值并且在调用列表中有一个以上的方法, 会发生如下情况
-
调用列表中最后一个方法返回的值就是委托调用返回的值
-
调用列表中其他方法的返回值都会被忽略
public delegate int MyDel1411();
class MyClass1411 { int intValue = 5; public int Add2() { intValue += 2; return intValue; } public int Add3() { intValue += 3; return intValue; } }
static void Main(string[] args) { MyClass1411 mc = new MyClass1411(); MyDel1411 mDel = mc.Add2; mDel += mc.Add3; mDel += mc.Add2; Console.WriteLine($"Value: {mDel?.Invoke()}"); }
12、调用带引用参数的委托
-
如果委托有引用参数, 参数值会根据调用列表的一个或多个方法的返回值而改变
-
在调用委托列表的下一个方法时, 参数的新值(不是初始值)会传递给下一个方法
public delegate void MyDel1412(ref int x);
class MyClass1412 { public void Add2(ref int x) { x += 2; } public void Add3(ref int x) { x += 3; }
static void Main(string[] args) { MyClass1412 mc = new MyClass1412(); MyDel1412 mDel = mc.Add2; mDel += mc.Add3; mDel += mc.Add2; int x = 5; mDel?.Invoke(ref x); Console.WriteLine($"Value = x: {x}"); //12 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了