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 块

相关推荐
wuyk55522 分钟前
98.C语言易混难点:字符数组与字符串指针的底层差异
c语言·开发语言·c++·stm32·嵌入式硬件·算法
峥无39 分钟前
从0到1手撕红黑树:封装实现 my_map 与 my_set(SGI-STL 源码级深度解析)
开发语言·c++·笔记·算法·stl
波特率11520043 分钟前
C++新特性---属性说明符与标准属性
开发语言·c++
程序员小八7771 小时前
上海百度B端java后端日常实习一面
java·开发语言
wp123_11 小时前
IPX8 防水 Type‑C连接器:安费诺 124018792112A 与 TONEVEE TY48087‑24A 技术梳理
c语言·开发语言
不会代码的小猴1 小时前
3. 控件学习1
开发语言·c++·笔记·qt·算法
fangzhanpeng1681 小时前
(前端)2.js变量作用域样例
开发语言·前端·javascript
mqiqe4 小时前
线程调度与 Schedulers:Project Reactor 并发模型的核心引擎
java·开发语言·网络
xixiaoyunya5 小时前
JavaScript 异步编程全解析:从回调地狱到 async/await 的演进之路
开发语言·javascript·ecmascript
zjnlswd5 小时前
C#学习笔记4
笔记·学习·c#