C#中的委托、匿名方法、Lambda、Action和Func

news/2024/10/26 17:46:53/

委托

委托概述

委托是存有对某个方法的引用的一种引用类型变量。定义方法的类型,可以把一个方法当作另一方法的参数。所有的委托(Delegate)都派生自 System.Delegate 类。委托声明决定了可由该委托引用的方法。

# 声明委托类型

委托类型声明与方法类似,可以理解为方法的类型,它与方法声明不同的地方:

  • 以delegate关键字开头
  • 没有方法主体
delegate void ShowInfo();//可带参数,可不带参数

它不需要在类内部声明,因为它是类型声明,委托可指向一个与其具有相同标签的方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace ConsoleApp2
{delegate void ShowInfo();public class Program{static void Main(string[] args){ShowInfo showinfo = ShowInfo;//把签名赋值给委托变量showinfo?.Invoke();//调用委托,可指向相同标签的方法}static void ShowInfo(){Console.WriteLine("打印ShowInfo方法");}}
}

运行结果:
在这里插入图片描述

创建委托实例

法一
第一种是使用带new关键字进行创建,操作组成如下:

  • 委托类型名称
  • 一组圆括号,其中参数列表为成员的方法的名称,该方法可以是实例方法也可以是静态方法
MyDel delVar;//声明委托类型的变量
MyDel delVar= new MyDel(实例方法);//创建委托并保存引用
MyDel delVar= new MyDel(静态方法);//创建委托并保存引用

法二
可以使用快捷语法,仅由方法说明符组成,因为在方法名称和其相对应的委托类型之间存在隐式转换,可以理解为方法赋值给委托变量

delVar = 实例方法;//创建委托并保存引用
delVar = 静态方法;//创建委托并保存引用

委托的调用

可以通过两种方式调用委托。一种是像调用方法一样调用委托,另外一种是使用委托的Invoke方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace ConsoleApp2
{delegate void Show();public class Test{//静态方法public static void Print1(){Console.WriteLine("打印静态方法");}//实例方法public void Print2(){Console.WriteLine("打印实例方法");}}public class Program{static void Main(string[] args){Test test = new Test();//1、调用方法一样调用委托Show show = test.Print2;//实例方法赋值给委托变量show();//调用委托Show show2 = Test.Print1;//静态方法赋值给委托变量show2();//调用委托//2、使用委托的Invoke方法show?.Invoke();//使用Invoke和空条件运算符show2?.Invoke();}}
}

委托的多播

委托对象可使用 “+” 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。“-” 运算符可用于从合并的委托中移除委托。

匿名方法

匿名方法提供了一种传递代码块作为委托参数的技术。匿名方法是没有名称只有主体的方法。在匿名方法中您不需要指定返回类型,它是从方法主体内的 return 语句推断的。
匿名方法表达式的语法包含如下组成部分:

  • delegate关键字
  • 参数列表,如果语句快没有使用任何参数则可以省略
  • 语句快,它包含了匿名方法的代码
delegate ( 参数 ) {语句块};

案例

using System.Text;
using System.Threading.Tasks;namespace ConsoleApp2
{delegate void Show();delegate int Add(int a, int b);public class Program{static void Main(string[] args){//不带参数Show show = delegate{Console.WriteLine("打印匿名方法");};show();//带参数Add add = delegate(int a, int b){int c = a + b;Console.WriteLine("和为多少:" + c);return c;};add(1,2);Console.ReadKey();}}
}

运行结果:
在这里插入图片描述

Lambda表达式

在匿名方法中,delegate关键字有点多余,因为编译器已经指定我们在将方法赋值给委托,因此我们可以利用Lambda表达式删除delegate关键字。在参数列表和匿名方法主体之间放置Lambda运算符=>。Lambda运算符读作"goes to"。如下代码演示这种转换。

MyDel del = delegate(int x) {return x+1};//匿名方法
MyDel del = (int x) =>{return x+1};//Lambda表达式

上面看起来简洁,但是只省略6个字符,然后,编译器可以推断更多的信息,因此我们可以进一步简化。

  • 编译器可以从委托声明指定委托参数的类型,因此Lambda表达式可以省略参数的类型。如del1
    • 如果只有一个隐式类型参数还可以省略圆括号。如del2
  • Lambda表达式运行表达式的主体是语句块或表达式,如果语句块包含了返回语句,则可以省略return关键字。如del3
MyDel del = delegate(int x) {return x+1};//匿名方法
MyDel del1 = (x) =>{return x+1};//Lambda表达式
MyDel del2 = x =>{return x+1};//Lambda表达式
MyDel del3 = x =>x+1;//Lambda表达式

Action 和Func

Action和Func都是.net内置的委托,可以使用他们以参数形式传递方法。他们都支持0-16个参数,然后Action没有返回值类型,Func有返回值类型,Func最后一个参数为返回值类型。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;namespace ConsoleApp2
{public class Program{static void Main(string[] args){#region{//不带参数Action act1 = () => { Console.WriteLine("打印"); };act1();//带1个参数Action<int> act4 = a => { Console.WriteLine("a="+a); };//这里不能省略{}act4(2);//不带参数,带返回值Func<int> func1 = () => { return 1; };func1();//带1个参数,带带返回值Func<int, int> func2 = a => {   int b = a + 1;Console.WriteLine("b=" + b);return b;};func2(2);}#endregionConsole.ReadKey();}}
}

http://www.ppmy.cn/news/1542177.html

相关文章

【云原生】Kubernets1.29部署StorageClass-NFS作为存储类,动态创建pvc(已存在NFS服务端)

文章目录 在写redis集群搭建的时候,有提到过使用nfs做storageclass,那时候kubernetes是1.20版本,https://dongweizhen.blog.csdn.net/article/details/130651727 现在使用的是kubernetes 1.29版本,根据之前的修改方式并未生效,反而提示:Error: invalid argument "Re…

Adobe Acrobat导致的电脑虚拟内存占用过大,开机一段时间后卡顿并自动关机

Adobe Acrobat导致的电脑虚拟内存占用过大&#xff0c;开机一段时间后卡顿并自动关机 问题描述解决方法 问题描述 电脑型号拯救者Y9000P&#xff0c;Win11系统&#xff0c;平时用着没什么问题&#xff0c;一段时间突然开机后不久就卡死&#xff0c;必须强制关机&#xff0c;通…

【flask web】 Blueprint 蓝图 路由模块化

Blueprint 蓝图的作用是&#xff1a;使路由模块化。 1、导入库包&#xff1a;这是是路由文件里面导入的哦 from flask import Blueprint例如&#xff1a; 2、导入蓝图配置 &#xff1a; from blueprints.auth import auth3、注册蓝图 app.register_blueprint(auth)创建蓝图…

Rust的move关键字在线程中的使用

为什么使用 move&#xff1f; 在 Rust 中&#xff0c;move 关键字主要用于闭包。当我们在一个线程中创建一个闭包并将其传递给另一个线程时&#xff0c;如果闭包中使用了某些变量&#xff0c;就需要决定这些变量的所有权归属。 不使用 move&#xff1a; 默认情况下&#xff0…

数据挖掘中的数据预处理:填充与主成分分析

数据挖掘中的数据预处理&#xff1a;填充与主成分分析 在数据挖掘中&#xff0c;数据预处理是非常重要的一步。现实世界中的数据通常是不完整的&#xff0c;包含噪声、缺失值或异常值&#xff0c;因此在进行模型训练或分析前&#xff0c;我们需要对数据进行清理和转换。本文将…

24.redis高性能

Redis的单线程和高性能 Redis是单线程吗&#xff1f; Redis 的单线程主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的&#xff0c;这也是 Redis 对外 提供键值存储服务的主要流程。 Redis 的多线程部分&#xff0c;比如持久化、异步删除、集群数据同步等&#xff…

[Qt] 信号与槽:深入浅出跨UI与跨线程的信号发送

文章目录 如何自定义信号并使用自定义信号的步骤1.使用 signals 声明信号2. 信号的返回值是 void3. 在需要发送信号的地方使用 emit4. 使用 connect 链接信号和槽5. 完整代码示例总结 如何跨UI发送信号Qt跨UI发送信号机制详解案例概述Qt 信号与槽机制简介代码逻辑详解主窗口 Wi…

单片机中的BootLoader(BootLoader简介和写法)

文章目录 前言一、BootLoader是什么二、最简单的bootloader的写法三、封装简单的串口程序前言 本篇文章我们来为大家开始讲解BootLoader,BootLoader使用也是非常广泛的,特别是和OTA远程升级相关的时候,所以我打算开一个专栏来给大家讲解这方面的内容。 一、BootLoader是什…