【一起来阅读《C#图解教程》吧】-- 委托
什么是委托
可以认为委托是持有一个或多个方法的对象,但是委托与典型的对象不同,你可以执行委托,委托会执行它所“持有”的方法。
你也可以将委托看成一个包含有序方法列表的对象,方法的列表称为调用列表,这些方法具有相同的签名和返回类型。
- 调用列表中的方法可以是实例方法也可以是静态方法。
- 在调用委托的时候,会执行其调用列表中的所有方法。
委托和类一样,是一种用户自定义的类型。但是类型表示的是数据和方法的集合,而委托则是持有一个或者多个方法,以及一系列的预定义操作。
上述的完整过程
//声明一个委托类型
delegate void MyDel(int value);
//委托类型的变量声明
MyDel delVar;
//创建委托对象
delVar = new MyDel(myInstObj.MyMethod); //创建委托并保存引用,第一个成员为实例方法。
delvar = new MyDel(SClass.OtherMethod); //创建委托并保存引用,第一个成员为静态方法。
//上面的创建委托对象,可以用快捷语句
delVar = myInstObj.MyMethod;
delVar = SClass.OtherMethod;
委托的赋值
由于委托是引用类型,我们可以通过给它赋值来改变包含在委托变量中的引用。旧的委托对象会被垃圾回收器回收。
delVar = myInstObj.MyMethod;
delVar = SClass.OtherMethod;
例如以上,第一次将方法方法myInstObj.MyMethod赋值给委托delVar,那么第二次将SClass.OtherMethod赋值给delVar时,旧的存放第一个方法的委托对象就会被垃圾回收。
组合委托
MyDel delVarA = myInstObj.MyMethod;
MyDel delVarB = SClass.OtherMethod;
MyDel delVarC = delVarA + delVarB;
组合之后的委托delVarC中包含两个分别来自delVarA和delVarB中的方法。而 delVarA delVarB委托则是不会产生变化。
添加和删除委托方法
//为委托增加方法
MyDel delVar = inst.MyM1;
delVar += SClass.m3;
delVar += X.Act;
//为委托删除方法
delVar -= X.Act;
在使用+=运算符时,实际发生的是创建了一个新的委托,其调用列表是左边的委托加上右边方法的组合。然后将这个新的委托赋值给delVar。
这实际上说明了一点,委托自创建之后就不会在产生变化,每次添加新的方法实际上是会产生一个新的委托,用来代替原来的委托。删除也是同理。
调用委托
如以上,MyDel类型的委托参数为一个int类型的值,则当我们调用委托时,需要传入的也是一个int类型的值。
MyDel delVar = inst.MyM1;
delVar += SClass.m3;
delVar += X.Act;
//调用
delVar(55);
使用参数调用委托就会使用相同的参数值(在这里是55)调用它的调用列表中的每一个成员。如果一个方法在调用列表中出现多次,当委托被调用时,每次在列表中遇到这个方法时它都会被调用一次。
调用带返回值的委托
如果委托有返回值并且在调用列表中有一个以上的方法,会发生下面的情况:
- 调用列表中最后一个方法返回的值就是委托调用返回的值
- 调用列表中所有其他方法的返回值都会被忽略。
class Program
{
static void Main(string[] args)
{
DeClass dc = new DeClass();
MyDel myDel = dc.Add2;
myDel += dc.Add3;
myDel += dc.Add2;
Console.WriteLine("Value:{0}",myDel);
Console.ReadKey();
}
}
class DeClass
{
private int v = 5;
public int Add2()
{
v += 2;
return v;
}
public int Add3()
{
v += 3;
return v;
}
}
//输出
输出结果:12
调用带有引用参数的委托
如果委托有引用参数,参数值会根据调用列表中的一个或多个方法的返回值而改变。也就是说调用列表里面的方法的参数并不一定是一开始的初始值,在调用委托列表中的下一个方法时,参数的新值(不是初始值)会传给下一个方法。
匿名方法
使用场景
- 声明委托变量时作为初始化表达式。
- 组合委托时在赋值语句的右边。
- 为委托增加事件时在赋值语句的右边。
语法
delegate (Parameters) {ImplementationCode}
// delegate 是关键字
//(Parameters) 是参数列表,举例如:(int x)
// {ImplementationCode} 是语句块。举例如:return x+1;
参数
除了数组参数,匿名方法的参数列表必须在如下3方面与委托匹配:参数数量;参数类型及位置;修饰符。
可以通过使圆括号为空或省略圆括号来简化若名方法的参数列表,但必须满足以下两个条件:
- 委托的参数列表不包含任何out参数;
- 匿名方法不使用任何参数。
//例如在下面这里,因为匿名方法未使用参数,则参数列表可以简化
delegate void SomeDel(int x);
SomeDel sDel = delegate
{
Debug();
CleanUp();
}
如果委托声明的参数列表包含了params参数,那么厝名方法的参数列表将忽略params关键字。
变量和参数的作用域
参数以及声明在匿名方法内部的局部变量的作用域限制在实现方法的主体之内
Lambda表达式
由于使用匿名方法还是存在语法上的麻烦,因此我们可以使用Lambda表达式。
delegate int MyDel(int x);
//匿名方法
MyDel meDel01 = delegate(int x) { return x + 1; };
//Lambda表达式
MyDel meDel02 = (int x) => { return x + 1; };
MyDel myDel03 = (x) => { return x + 1; };
MyDel myuDel04 = x => { return x + 1; };
MyDel myDel05 = x => x + 1;
- 带有类型的参数列表称为显式类型。
- 省略类型的参数列表称为隐式类型。
- 如果只有一个隐式类型参数,我们可以省略周围的圆括号
- 最后,Lam a表达式允许表达式的主体是语句块或表达式。如果语句块包含了一个返回语句,我们可以将语句块替换为return关键字后的表达式
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律