c#lambad表达式

lambad表达式的概念

可以将lambad表达式 理解为匿名函数的简写

它除了写法不同外

使用上和匿名函数一模一样

都是和委托或者事件 配合使用的

lambad表达式语法

匿名函数

cs 复制代码
delegate (参数列表)
{

};

lambad表达式

cs 复制代码
   (参数列表) =>
   {
       //函数体
   };

使用

1.无参无返回

cs 复制代码
 Action a = () =>
 {
     Console.WriteLine("无参无返回值的lambad表达式");
 };
 a();

2.有参

cs 复制代码
 Action<int> a2 = (int value) =>
 {
     Console.WriteLine("有参数Lambad表达式{0}", value);
 };
 a2(100);

3.甚至参数类型都可以省略 参数类型和委托或事件容器一致

cs 复制代码
Action<int> a3 = (value) =>
{
    Console.WriteLine("省略参数类型的写法{0}", value);
};
a3(200);

4.有返回值

cs 复制代码
 Func<string, int> a4 = (value) =>
 {
     Console.WriteLine("有返回值有参数的那么大表达式{0}", value);
     return 1;
 };

闭包

当一个匿名函数(Lambda 表达式或匿名委托)引用了它外部作用域的变量时,编译器会自动将这些变量的生存期延长,使得它们不会因为原始作用域结束而被销毁,而是与委托实例一同存活。

内层的函数可以引用包含在它外层的函数的变量

即使外层函数的执行已经终止

注意:

该变量提供的值并非变量创建时的值,而是在父函数范围内的最终值。

cs 复制代码
 class Test
 {
     public event Action action;

     public Test()
     {
         int value = 10;
         //这里就形成了闭包
         //因为 当构造函数执行完毕时  其中申明的临时变量value的声明周期被改变了
         action = () =>
         {
             Console.WriteLine(value);
         };

         for (int i = 0; i < 10; i++)
         {
             //此index 非彼index
             int index = i;
             action += () =>
             {
                 Console.WriteLine(index);
             };
         }
     }

     public void DoSomthing()
     {
         action();
     }
 }

第一个闭包Value

value 是构造函数的局部变量

普通情况下,构造函数执行完毕后,value 应该被销毁。

但是 action = () => Console.WriteLine(value); 这个 Lambda 使用了 value

编译器会发现这个引用,于是在幕后做这件事:

1.生成一个隐藏类 (例如 c__DisplayClass0_0),里面有一个公共字段 value

2.把 value 从栈上的局部变量提升到这个隐藏类的实例字段中。

3.把 Lambda 的方法体变成这个隐藏类的成员方法。

4.最后,action 委托引用了这个隐藏类实例的方法。

结果:value 不再随构造函数结束而消亡,而是action 委托一起存活 。即使 Test 对象创建完毕,value 依然被委托牢牢"抓住"。

第二个闭包:循环中的闭包 捕获 index

每次循环都创建一个新的局部变量 index ,并赋值为当前的 i

每个 Lambda 捕获的是自己那个循环迭代中的 index

编译器同样为每个 Lambda 生成一个隐藏类的实例(或复用同一个隐藏类但不同的字段,具体取决于编译器实现),每个实例持有各自的 index 副本。

因此,10 次循环会创建 10 个不同的捕获变量,互不干扰。

为什么不能直接捕获 i

闭包捕获的是变量容器 ,不是

for循环整个共用一个变量。

多个委托可以捕获同一个容器,从而相互影响。

要让每个委托独立,就要为每个委托创建独立的变量容器。

核心是 编译器会为每个不同的"捕获作用域"生成一个隐藏类,所有捕获相同外部变量的匿名函数可能会共享同一个隐藏类实例。

不同的捕获作用域会导致不同的隐藏类;同一个作用域内的多个变量会被合并到一个隐藏类中

value是一个作用域下,一个隐藏类,一个类实例。

index是一个作用域下,一个隐藏类,10个不同类实例。

要是一个作用域下,多个变量,也是一个类,类中存放多个字段保存变量。

作用域 指的是程序中变量可以被访问的代码区域

一个变量从声明开始,到它所在的 { } 结束,这段范围就是它的作用域。方法体、循环体、if 块

相关推荐
EIP低代码平台9 分钟前
EIP低代码平台-系统参数配置详解|落地三级等保+高灵活私有化部署方案
低代码·c#·权限·工作流·netcore
Echo缘43 分钟前
嵌入式系统C语言资源分类与内存分布分析
c语言·开发语言
JaneConan1 小时前
鸿蒙 ArkUI 深水区:@Watch 和 @Observed,状态变了「自动跑」+ 嵌套对象「深层重绘」
开发语言·后端·ui·harmonyos
赤水无泪1 小时前
qt中图标、名称的设置方式
开发语言·qt
王莎莎-MinerU1 小时前
MCP 解决的是工具接入,科研 Agent 还缺的是科学证据接口标准化
开发语言·网络·人工智能·深度学习·pdf·c#·php
橘子海全栈攻城狮2 小时前
【最新源码】基于SpringBoot + Vue的超市管理系统的设计与实现D002
java·开发语言·vue.js·spring boot·后端·spring
在水一缸2 小时前
深入浅出 Catch2:现代 C++ 测试框架的优雅实践
开发语言·c++·单元测试·log4j·测试框架·catch2
-银雾鸢尾-2 小时前
C#中Object类内的方法
开发语言·c#
浮江雾2 小时前
Flutter第十节-----Flutter布局与组件全解析
android·开发语言·前端·学习·flutter·入门
爱喝水的鱼丶2 小时前
SAP-ABAP:ALV跨版本兼容指南——适配ECC与S4 HANA系统的ALV开发注意事项
开发语言·性能优化·sap·abap·经验交流