【从零开始入门unity游戏开发之——C#篇34】C#匿名函数(delegate )和Lambda表达式

文章目录

  • 一、匿名函数(`delegate` )
    • 1、什么是匿名函数?
    • 2、匿名函数的基本语法
      • 2.1 语法
      • 2.2 **没有参数的匿名函数:**
      • 2.3 **有参数的匿名函数:**
      • 2.4 **有返回值的匿名函数:**
    • 3、匿名函数的使用示例
      • 3.1 作为参数传递匿名函数
      • 3.2 作为返回值返回匿名函数
    • 4、匿名函数的缺点
      • 4.1 无法单独移除
      • 4.2 匿名函数难以调试
      • 4.3 性能开销
    • 5. 匿名函数与闭包
    • 6、匿名函数的总结
  • 二、Lambda表达式
    • 1 、什么是 Lambda 表达式
    • 2、Lambda 表达式的语法
    • 3、匿名函数转Lambda 表达式示例
    • 4、Lambda 表达式的使用
      • 4.1 **无参无返回值**:
      • 4.2 **有参的无返回值**:
      • 4.3 **有返回值**:
    • 5、闭包
      • 5.1 概念
      • 5.2 示例
      • 5.3 如何避免这种问题?
    • 5、总结
    • 6、注意:
  • 三、委托和匿名函数的区别
  • 专栏推荐
  • 完结

一、匿名函数(delegate

1、什么是匿名函数?

匿名函数是没有名字的函数。它通常用于在需要传递函数或行为时,避免了定义一个额外的命名函数。匿名函数最常用的场景是在委托(delegate)和事件(event)的处理过程中。

常见使用场景:

  • 委托传递时
  • 事件绑定时

2、匿名函数的基本语法

2.1 语法

匿名函数使用delegate关键字来声明,语法如下:

delegate (参数列表) { 函数逻辑 };

2.2 没有参数的匿名函数:

Action a = delegate {Console.WriteLine("匿名函数逻辑");
};
a();

2.3 有参数的匿名函数:

Action<int, string> b = delegate (int a, string b) {Console.WriteLine(a);Console.WriteLine(b);
};
b(108, "123");

2.4 有返回值的匿名函数:

Func<string> c = delegate {return "返回的字符串";
};
Console.WriteLine(c());

3、匿名函数的使用示例

3.1 作为参数传递匿名函数

可以将匿名函数作为参数传递给方法:

public void DoSomething(int a, Action fun)
{Console.WriteLine(a);fun(); // 调用传入的匿名函数
}// 调用方法时传递匿名函数
DoSomething(10, delegate {Console.WriteLine("传入的匿名函数逻辑");
});

3.2 作为返回值返回匿名函数

匿名函数可以作为方法的返回值:

public Action GetFun()
{return delegate {Console.WriteLine("匿名函数返回值");};
}Action action = GetFun();
action();

直接调用返回的委托函数

GetFun()();  // 直接调用返回的匿名函数

4、匿名函数的缺点

4.1 无法单独移除

匿名函数没有名称,因此无法通过直接引用来移除它们。尤其在委托或事件中,当添加多个匿名函数时,无法移除某一个匿名函数。

例如:

Action ac = delegate {Console.WriteLine("匿名函数一");
};ac += delegate {Console.WriteLine("匿名函数二");
};ac();  // 会打印 "匿名函数一" 和 "匿名函数二"ac -= delegate {Console.WriteLine("匿名函数二");
};  // 编译错误:不能移除匿名函数ac();  // 依然打印 "匿名函数一" 和 "匿名函数二"

由于匿名函数没有名称,无法通过-=运算符去移除某一个特定的匿名函数。

4.2 匿名函数难以调试

因为匿名函数没有名称,所以它们难以调试。无法直接断点到匿名函数内,也无法追踪其调用栈。

4.3 性能开销

在某些情况下,匿名函数会增加额外的闭包和委托创建的性能开销,尤其是当它们在频繁调用的场景中使用时。

5. 匿名函数与闭包

匿名函数在使用时可以捕获外部变量(即使外部变量在匿名函数外部的作用域中已经超出了生命周期),这被称为闭包

例如:

int x = 10;
Action action = delegate {Console.WriteLine(x);  // 捕获了外部变量x
};
x = 20;
action();  // 打印 20

这个例子中,匿名函数捕获了外部变量x,并且打印了x的当前值。由于匿名函数形成闭包,它保存了对x的引用,即使x的值被修改,匿名函数依然会使用最新的值。

6、匿名函数的总结

  • 定义简洁:匿名函数没有名称,可以直接在需要的地方声明并使用,适用于委托和事件的传递。
  • 用途广泛:尤其在回调函数、事件处理、LINQ表达式等场景中非常常见。
  • 缺点:无法移除、调试困难、性能开销较大等。
  • 闭包特性:匿名函数可以捕获外部变量(闭包),这使得它们能够访问外部作用域的变量。

二、Lambda表达式

1 、什么是 Lambda 表达式

Lambda 表达式可以被看作是匿名函数的简写。它与匿名函数的区别在于,写法更为简洁,且与委托或者事件配合使用的方式相同。

  • 匿名函数:没有名称的函数,通常用 delegate 关键字定义。
  • Lambda 表达式:更简洁的函数表示法,使用 => 符号。

2、Lambda 表达式的语法

Lambda 表达式的语法格式如下:

(parameters) => expression_or_statement_block
  • 参数列表:Lambda 表达式的输入参数,可以省略类型,C# 会根据上下文推断类型。
  • 表达式或语句块:Lambda 表达式的执行代码。如果是单个表达式,返回值会被自动推断。如果是多行代码,必须用 {} 包裹。

3、匿名函数转Lambda 表达式示例

  • 匿名方法(使用 delegate):

    delegate void MyDelegate(int x);
    MyDelegate d = delegate(int x) { Console.WriteLine(x); };
    d(10);
    
  • Lambda 表达式

    Action<int> d = (int x) => { Console.WriteLine(x); };
    d(10);
    

4、Lambda 表达式的使用

4.1 无参无返回值

Action a = () => Console.WriteLine("无参无返回值的 Lambda 表达式");
a();

4.2 有参的无返回值

Action<int> a2 = (int value) => Console.WriteLine($"有参数的 Lambda 表达式 {value}");
a2(100);

可以省略参数类型

Lambda 表达式的参数类型可以根据委托类型自动推断,所以可以省略参数类型。

Action<int> a3 = (value) => Console.WriteLine($"省略参数类型的写法 {value}");
a3(200);

4.3 有返回值

使用 Func 委托时,Lambda 表达式可以有返回值。

Func<string, int> a4 = (value) =>
{Console.WriteLine($"有返回值的 Lambda 表达式 {value}");return 1;
};
Console.WriteLine(a4("123123"));

5、闭包

5.1 概念

  • 闭包 是 Lambda 表达式捕获外部作用域中的变量的机制。
  • Lambda 表达式不仅仅捕获变量的值,而是捕获了变量的引用。它可以在 Lambda 表达式的执行时继续访问这些变量,即使这些变量所在的作用域已经结束。

5.2 示例

闭包常常会在循环中表现出意外的行为,因为 Lambda 表达式捕获了循环变量的引用,而不是它的值。以下是一个例子:

public class ClosureInLoop
{public void Test(){List<Action> actions = new List<Action>();for (int i = 0; i < 5; i++){// Lambda 表达式捕获了循环变量 i 的引用actions.Add(() => Console.WriteLine(i));}// 输出的结果是 5 次 5,因为 Lambda 捕获的是 i 的引用,而不是它的值foreach (var action in actions){action();}}
}

解释:

在上面的代码中,我们将 Lambda 表达式添加到一个列表中。每个 Lambda 表达式都捕获了循环变量 i 的引用。因为 Lambda 表达式没有立即执行,而是在循环结束后才被执行,所以它们访问的是最终的 i 值(即 5)。所有的 Lambda 表达式都会输出 5,而不是它们在创建时的 i 值。

5.3 如何避免这种问题?

如果你希望 Lambda 表达式捕获的是 i 在每次迭代时的值,而不是循环结束后的值,你可以在 Lambda 表达式中引入一个局部变量来保存当前的 i 值:

public class ClosureInLoopFix
{public void Test(){List<Action> actions = new List<Action>();for (int i = 0; i < 5; i++){int capturedValue = i;  // 将 i 的值保存到一个局部变量actions.Add(() => Console.WriteLine(capturedValue));}foreach (var action in actions){action();  // 现在会输出 0, 1, 2, 3, 4}}
}

在这种情况下,capturedValue 是在每次循环时创建的一个新的局部变量,这样每个 Lambda 表达式都会捕获不同的 capturedValue,而不是 i 的引用。

5、总结

  • Lambda 表达式 是匿名函数的简化写法,通常用于委托或事件处理。
  • 语法(参数列表) => 表达式/语句块
  • 闭包:Lambda 表达式可以捕获外部函数的局部变量,并且可以在外部函数已经结束后依然访问这些变量。

6、注意:

  • Lambda 表达式使代码更简洁,但缺点是无法明确地移除或管理。
  • 闭包 可能导致意外的引用或性能问题,特别是在循环或多次调用 Lambda 时。

三、委托和匿名函数的区别

C# 中的匿名函数和委托确实有一些相似之处,尤其是在代码外观上可能会让人觉得它们很像,但它们并不是同一个概念。

  • 委托 是一种类型,它定义了方法的签名,并可以引用任何符合该签名的方法。
  • 匿名函数 是没有显式名称的函数,它们可以在声明时立即定义行为,包括匿名方法和 Lambda 表达式。
  • 委托和匿名函数一起使用:匿名函数可以被赋值给委托类型的变量,从而实现更灵活和简洁的编程风格。
  • delegate 关键字 主要用于定义委托类型,但在匿名方法中也会出现,用于直接定义函数体。Lambda 表达式则不需要显式的 delegate 关键字。

专栏推荐

地址
【从零开始入门unity游戏开发之——C#篇】
【从零开始入门unity游戏开发之——unity篇】
【制作100个Unity游戏】
【推荐100个unity插件】
【实现100个unity特效】
【unity框架开发】

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/65423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IDEA开发Java应用的初始化设置

一、插件安装 如下图所示&#xff1a; 1、Alibaba Java Coding Guidelines 2.1.1 阿里开发者规范&#xff0c;可以帮忙本地自动扫描出不符合开发者规范的代码&#xff0c;甚至是代码漏洞提示。 右击项目&#xff0c;选择《编码规约扫描》&#xff0c;可以进行本地代码规范扫…

代码模拟打字机(python)

回车符\r打印稿纸&#xff0c;time.sleep模拟停顿效果&#xff0c;一顿一顿的打字机效果就此呈现。 (笔记模板由python脚本于2024年12月27日 19:34:37创建&#xff0c;本篇笔记适合有基础编程能力的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.…

让 AMD GPU 在大语言模型推理中崭露头角:机遇与挑战

在当今科技飞速发展的时代&#xff0c;大语言模型&#xff08;LLM&#xff09;的兴起彻底改变了人工智能领域的格局。从智能客服到文本生成&#xff0c;从知识问答到代码编写辅助&#xff0c;大语言模型的应用无处不在&#xff0c;深刻影响着我们的生活和工作。然而&#xff0c…

LLMs之o3:《Deliberative Alignment: Reasoning Enables Safer Language Models》翻译与解读

LLMs之o3&#xff1a;《Deliberative Alignment: Reasoning Enables Safer Language Models》翻译与解读 导读&#xff1a;2024年12月&#xff0c;这篇论文提出了一种名为“审慎式对齐 (Deliberative Alignment)”的新方法&#xff0c;旨在提高大型语言模型 (LLM) 的安全性。论…

音视频入门基础:MPEG2-TS专题(24)——FFmpeg源码中,显示TS流每个packet的pts、dts的实现

音视频入门基础&#xff1a;MPEG2-TS专题系列文章&#xff1a; 音视频入门基础&#xff1a;MPEG2-TS专题&#xff08;1&#xff09;——MPEG2-TS官方文档下载 音视频入门基础&#xff1a;MPEG2-TS专题&#xff08;2&#xff09;——使用FFmpeg命令生成ts文件 音视频入门基础…

微信流量主挑战:用户破16!新增文档转换(新纪元3)

朋友们&#xff0c;报告好消息&#xff01;我的小程序用户数量已经涨到16个了&#xff01;没错&#xff0c;真没拉朋友圈亲戚好友来撑场子&#xff0c;全靠实力&#xff08;和一点点运气&#xff09;吸引了16位陌生小伙伴光临&#xff01;这波进步&#xff0c;连我自己都感动了…

顶顶通呼叫中心中间件mod_cti模块安全增强,预防盗打风险(mod_cti基于FreeSWITCH)

文章目录 前言联系我们mod_cti版本支持安全加强说明 前言 FreeSWITCH暴露在公网最大的风险就是被不法之人盗打 出现盗打的主要原因以下几点&#xff1a; 分机密码太简单或者密码泄露了拨号方案配置不合理sofia配置错误 所以我们给顶顶通呼叫中心中间件添加了安全加强功能&am…

【Halcon】例程讲解:基于形状匹配与OCR的多图像处理(附图像、程序下载链接)

1. 开发需求 在参考图像中定义感兴趣区域&#xff08;ROI&#xff09;&#xff0c;用于形状匹配和文本识别。通过形状匹配找到图像中的目标对象位置。对齐多幅输入图像&#xff0c;使其与参考图像保持一致。在对齐后的图像上进行OCR识别&#xff0c;提取文本和数字信息。以循环…

产品初探Devops!以及AI如何赋能Devops?

DevOps源自Development&#xff08;开发&#xff09;和Operations&#xff08;运维&#xff09;的组合&#xff0c;是一种新的软件工程理念&#xff0c;旨在打破传统软件工程方法中“开发->测试->运维”的割裂模式&#xff0c;强调端到端高效一致的交付流程&#xff0c;实…

python+PyMuPDF库:(一)创建pdf文件及内容读取和写入

目录 文档操作 打开文档 获取文档信息 删除页 复制页 移动页 选择重构合并 保存关闭 页对象操作 内容读取 获取页对象的字体样式 插入文本标签 插入文本内容 字体设置 insert_text添加文本 insert_textbox添加文本 插入图片 获取页面注释、链接、表单字段 …

开源诊断工具Arthas

说明&#xff1a; 1、需要先要安装配置好jdk。 2、你的虚拟机得有网&#xff0c;没有网就按照压缩包上传解压。然后直接看三 一、官网 https://arthas.aliyun.com/doc/quick-start.html#_1-%E5%90%AF%E5%8A%A8-math-game 二、下载和卸载 # 下载 curl -O https://arthas.al…

VisionPro开发使用交互反馈系统(Affordance System)

XR Interaction Toolkit 提供了一个affordance system 可供性系统&#xff0c;使用户能够创建对交互状态的视觉和听觉反馈。一般的信息流从向Affordance State Provider场景中添加一个&#xff08;通常是可交互的&#xff09;并将其指向我们要监视其交互状态的可交互对象开始。…

如何在 Ubuntu 22.04 上安装并开始使用 RabbitMQ

简介 消息代理是中间应用程序&#xff0c;在不同服务之间提供可靠和稳定的通信方面发挥着关键作用。它们可以将传入的请求存储在队列中&#xff0c;并逐个提供给接收服务。通过以这种方式解耦服务&#xff0c;你可以使其更具可扩展性和性能。 RabbitMQ 是一种流行的开源消息代…

力扣矩阵-算法模版总结

lc-73.矩阵置零-(时隔14天)-12.27 思路&#xff1a;(23min22s) 1.直接遍历遇0将行列设0肯定不行&#xff0c;会影响后续判断&#xff0c;题目又要求原地算法&#xff0c;那么进一步考虑是否可以将元素为0&#xff0c;其行列需要设为0的位置给存储下来&#xff0c;最后再遍历根据…

OCR实践-问卷表格统计

前言 书接上文 OCR实践—PaddleOCROCR实践-Table-Transformer 本项目代码已开源 放在 Github上&#xff0c;欢迎参考使用&#xff0c;Star https://github.com/caibucai22/TableAnalysisTool 主要功能说明&#xff1a;对手动拍照的问卷图片进行统计分数&#xff08;对应分数…

yarn list --pattern vuex-module-decorators

dgqdgqdeMac-mini spid-admin % yarn list --pattern vuex-module-decorators yarn list v1.22.22 └─ vuex-module-decorators0.16.1 ✨ Done in 0.24s.好的&#xff0c;这段代码是一个典型的 Vuex 模块定义&#xff0c;使用了 vuex-module-decorators 库。这个库为 Vuex 提…

用Python写炸金花游戏

文章目录 **代码分解与讲解**1. **扑克牌的生成与洗牌**2. **给玩家发牌**3. **打印玩家的手牌**4. **定义牌的优先级**5. **判断牌型**6. **确定牌型优先级**7. **比较两手牌的大小**8. **打印结果** 完整代码 以下游戏规则&#xff1a; 那么我们要实现的功能&#xff0c;就是…

day19-Linux软件包

科普&#xff0c;什么是代码文件。 电脑程序Program&#xff0c;就是某一个编程语言编写的一个代码文件&#xff0c;里面包含了该语言特有的指令&#xff0c;以及各种字符、符号。 linux自带的network管理脚本&#xff0c;shell脚本 什么是软件程序。 软件程序&#xff0c;就…

图像处理-Ch4-频率域处理

Ch4 频率域处理(Image Enhancement in Frequency Domain) FT &#xff1a;将信号表示成各种频率的正弦信号的线性组合。 频谱&#xff1a; ∣ F ( u , v ) ∣ [ R 2 ( u , v ) I 2 ( u , v ) ] 1 2 |F(u, v)| \left[ R^2(u, v) I^2(u, v) \right]^{\frac{1}{2}} ∣F(u,v)…

Vue BPMN Modeler流程图

1、参考地址 git clone https://github.com/evanyangg/vue-bpmn-modeler.git 2、安装bpmn.js npm install bpmn-js --save 3、使用bpmn.js <template><div class"containers"><div class"canvas" ref"canvas"></div&g…