综述:委托、匿名方法、lambda表达式、事件
委托的意义在于:通过委托把函数当成方法参数来传递,以便方法内部调用额外传过来的处理逻辑。
(定义委托类型→声明委托变量→实例化委托变量(附加方法)→作为参数传递给目标方法→目标方法内调用委托)
匿名方法的意义在于:快速方便的实例化委托,不用定义具体的方法来关联委托,就是临时定义个方法(处理逻辑)与委托相关联。
lambda表达式的意义在于:简化匿名方法的定义,更方便的实例化委托。
事件的意义在于:??
匿名方法允许我们避免使用独立的具名方法。总之匿名方法是为了节省代码,避免正式的声明只用一次的方法;还有Lambda表达式,也是为了简化匿名方法;
认识委托
官网文档:委托 - C# 编程指南 | Microsoft Learn
委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。 在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联。 你可以通过委托实例调用方法。
委托的定义类似方法,用关键字delegate
如:public delegate string TestDelegate(string inputStr);
c#中的委托可以理解为函数的一个包装,它使得c#中的函数可以作为参数来被传递。可以把委托看做一个包含有序方法列表的对象,这些方法具有相同的签名和返回类型。
方法签名包括方法名、方法参数的个数、类型和顺序
委托使得c#中的函数可以作为另一个函数的参数来被传递,这样可以实现比如说回调的功能。
委托的本质
你定义一个委托类型,编译器会把它编译成一个继承自System.MulticastDelegate的子类。父类拥有一个构造函数和3个虚方法。因为有构造函数,故委托变量可以用new来实例化。
运算符重载:表面上扩展了运算符实际上是方法的扩展。
使用委托的步骤
- 定义委托类型
- 声明委托变量
- 实例化委托变量(附加方法)
- 作为参数传递给目标方法
- 目标方法内调用委托
也可以在实例化委托变量即附加相关方法后,直接调用委托来回调关联的方法;
实例化委托的方式
委托是引用类型,创建委托对象,或者说实例化委托,有三种方法:
eg:Delegate void MyDel (int x) ;
MyDel md1=new MyDel (new ClassA().M1);
MyDel md2 = new ClassA().M1;
//之间存在隐式转换,注意,用来实例化委托的具名方法是不带括号的;MyDel md3= x=>{ x=100+x; } ;
//使用lamada表达式实例化委托变量
委托链
它是委托类型,把链接了多个方法的委托称为委托链或多路广播委托(它封装了对对象方法引用的数组)。在调用委托链时,被绑定到委托链中的每个方法都会被调用,且调用顺序是先绑定先调用。
使用如:MyDel theChain=null; theChain+=md; theChain+=mc;
调用:theChain(); //先执行md,再执行mc
委托还可以组合,即; MyDel md3=md1+md2;
.net 类库中常用的委托
Action<T1,T2,……>
无返回值的处理逻辑,用它。
Func<T1,T2,……,TResult>
有返回值的处理逻辑,用它。
匿名方法
匿名方法就是没有名字的方法,因为没有名字,所以只能在函数定义的时候被调用,在其他任何情况下都不能被调用,所以不具有复用性;编译器在编译匿名方法时会为其生成一个方法名。
匿名方法与委托结合使用:
在实例化委托变量时,不直接赋予它一个定义好了的方法,而是直接“现做现卖”。
格式:委托类型 变量名 = delegate( 形参 ) { 逻辑处理语句 };
比如:td1 += delegate (int a, string n) { $"Hi {n},你一顿吃{a}个馒头??";};
调用时直接用:变量名(实参);这个调用是隐式调用方式。
如果形参是无参的,delegate后面的括号不要写,直接跟大括号,里面写实现代码就行了;如果形参有参数,那括号就别省;
如果委托有返回值,那么匿名方法的方法体中的return后面一定要跟与委托返回值类型兼容的值(如其子类、实现类的相应对象)
闭包延长外部变量的生命周期:
匿名方法的缺点:不能在其他地方被调用,即不具有复用性。 而且,匿名方法会将自动形成闭包。当一个函数(这里称为外部函数)包含对另一个函数(内部函数)的调用时,或内部函数使用了外部函数的变量时都会形成闭包。对于一个被捕获的变量(匿名方法内使用匿名方法外的变量)而言,只要还有任何委托实例在引用它,它就一直存在,就不会在部分委托实例调用结束后被垃圾回收释放掉。
对于匿名方法捕捉到的变量,编译器会额外创建一个类来容纳他们,可通过IL来查看。
Lambda表达式
由来:是为了简化匿名方法,减少代码;
简介:Lambda表达式可以理解为一个匿名方法,使用 =>
操作符(读作goes to),它在一行代码中声明方法的参数,以及方法的逻辑。用于创建委托实例或转换为表达式树。
写法上, =>
的左边是匿名方法的输入参数(形参),右边是表达式或语句块。
左边:形参无论多少个,不需要声明类型,c#编译器会推断出类型,若只有一个参数,不用写括号,0个或1个以上的参数需要括号。
右边:表达式或语句块,如果只有一句,不用写
{}
,如果有好几句,那就得需要了。另外如果只有一句,则不需要写 return 关键词,其结果会自动作为方法返回值。
Lambda 表达式是作为对象处理的代码块(表达式或语句块)。 它可作为参数传递给方法,也可通过方法调用返回。
演变过程
》c#1.0中创建委托实例,是用一个另外定义的具体方法
》c#2.0中可以用匿名方法来创建委托实例,此时就不需要额外定义回调方法即委托关联的方法了。
》c#3.0用Lambda表达式来创建委托实例。
使用:在实际开发过程中,委托的用途莫过于订阅事件了,lambda表达式的作用可以是订阅事件。总之,他就是结合委托使用的。
表达式也有树结构----表达式树。
作用:为学习Linq to SQL做铺垫。
解释:可以理解为一种数据结构,即类似与数据结构课程中的栈和队列,只不过表达式树用于表示Lambda表达式的逻辑罢了。
事件
定义格式: 访问修饰符(最好public) event 委托类型 事件名 ;
事件是建立在委托的基础之上的。它涉及两个类(不太准确),事件发布者和事件订阅者。
事件订阅者需要订阅(实例化)事件发布者发布的事件,以便在事件被触发时接受消息并作出处理。用+=订阅,-=取消订阅。
使用步骤:
- 自定义委托,也可以用系统的EventHandler
- 用该委托定义事件;
- 发出事件;实际就是一个函数,返回类型和签名同委托(不太确定),里 面触发事件的语句(函数调用)是:事件名(实参); 这样会调用与委托关联的函数。
- 以上三点可以写在发布者类里。事件处理写在订阅者类里,它就是一个可以与委托关联(实例化委托变量)的函数,该函数里面对发布者进行回应;
- 事件的订阅:事件名 +=与委托关联的方法(即实例化委托变量时 等号的右半部分);
- 发出通知:调用之前“发出事件”时定义的函数。然后各个订阅者就可以有所反应了。
事件相关的常见委托类型
EventHandler
是.NET类库中预定义的委托类型,它只用于处理不包含事件数据的事件。如果我们想在这种方式定义的事件中包含事件数据,则可以通过派生EventArgs
类来实现。
事件的本质
特殊的多路广播委托(委托链)。c#事件提供了对私有委托字段进行访问的有效方法。 验证可以查看IL代码。c#中的事件被编译成包含一字段(私有委托变量)和两个公共方法的代码段。两个公共方法中,一个带有add_
前缀,一个带有remove_
前缀,前缀后面是事件名称。Add前缀方法是通过调用Delegate.Combine()
方法来实现的,该方法将多个委托组合成了一个多路广播委托(委托链),相应的,remove前缀的方法是通过间接调用Delegate.Remove()
方法,该方法用于将一个委托从委托链中字段移除。这个私有的委托类型变量,用于保存对事件处理方法的引用,注意该委托类型的变量为私有,只能从定义该事件的类中进行访问。
更新于:2023-05-02
标签:调用,委托,c#,匿名,实例,事件,方法,lambda From: https://www.cnblogs.com/idasheng/p/17368121.html