c#lambad表达式
lambad表达式的概念可以将lambad表达式 理解为匿名函数的简写它除了写法不同外使用上和匿名函数一模一样都是和委托或者事件 配合使用的lambad表达式语法匿名函数delegate (参数列表) { };lambad表达式(参数列表) { //函数体 };使用1.无参无返回Action a () { Console.WriteLine(无参无返回值的lambad表达式); }; a();2.有参Actionint a2 (int value) { Console.WriteLine(有参数Lambad表达式{0}, value); }; a2(100);3.甚至参数类型都可以省略 参数类型和委托或事件容器一致Actionint a3 (value) { Console.WriteLine(省略参数类型的写法{0}, value); }; a3(200);4.有返回值Funcstring, int a4 (value) { Console.WriteLine(有返回值有参数的那么大表达式{0}, value); return 1; };闭包当一个匿名函数Lambda 表达式或匿名委托引用了它外部作用域的变量时编译器会自动将这些变量的生存期延长使得它们不会因为原始作用域结束而被销毁而是与委托实例一同存活。内层的函数可以引用包含在它外层的函数的变量即使外层函数的执行已经终止注意该变量提供的值并非变量创建时的值而是在父函数范围内的最终值。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(); } }第一个闭包Valuevalue是构造函数的局部变量。普通情况下构造函数执行完毕后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 块