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 块

相关推荐
文静小土豆1 天前
Java 应用上 K8s 全指南:从部署到治理的生产级实践
java·开发语言·kubernetes
西西弗Sisyphus1 天前
Python 在终端里彩色打印
开发语言·python·print·彩色打印
Rsun045511 天前
3、Java 工厂方法模式从入门到实战
java·开发语言·工厂方法模式
wjs20241 天前
C++ 基本的输入输出
开发语言
码云数智-园园1 天前
Python的GIL锁如何影响多线程性能?有哪些替代方案?
开发语言
咬_咬1 天前
go语言学习(map)
开发语言·学习·golang·map
古城小栈1 天前
rustup 命令工具,掌控 Rust 开发环境
开发语言·后端·rust
NQBJT1 天前
嵌入式从零开始(第十二篇):调试与工具链 —— 从 IDE 到逻辑分析仪
ide·stm32·单片机·嵌入式硬件·c#
lly2024061 天前
NumPy 高级索引
开发语言
XY_墨莲伊1 天前
【编译原理】实验二:基于有穷自动机FA词法分析器设计与实现
c语言·开发语言·c++·python