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 块

相关推荐
峥嵘life6 分钟前
Android getprop 属性限制详解:User 版本属性获取问题分析
android·开发语言·python·学习
郝学胜-神的一滴7 分钟前
Qt 高级开发 019:从零定制登录窗口按钮、Logo 样式与交互悬浮效果
开发语言·c++·qt·程序人生·交互·用户界面
星夜夏空9912 分钟前
FreeRTOS学习(5)——内存映射
开发语言·学习
yujunl26 分钟前
resx文件上具有 Web 标记
开发语言
catchadmin28 分钟前
免费可商用 PHP 管理后台 CatchAdmin V5.3.1 发布 后台打包直降 5s 内
开发语言·php
YY&DS38 分钟前
Qt Designer 自定义控件已提升后,如何修改提升类
开发语言·qt
右耳朵猫AI1 小时前
Rust技术周刊 2026年第19周
开发语言·后端·rust
Leweslyh1 小时前
基于 Confucius 架构的无人集群网络控制原语解析
开发语言·网络·php
月落归舟1 小时前
Java线程小记
java·开发语言
摇滚侠1 小时前
01 基础语法 JavaScript 入门到精通全套教程
开发语言·javascript·ecmascript