zoukankan      html  css  js  c++  java
  • 防止Lambda的各种坑爹(一)

       1.奇怪的被捕获的变量: 

    View Code
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace TestLambda
     8 {
     9     class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13             Action action = CreateAction();
    14             action();
    15             action();
    16             action();
    17             Console.Read();
    18         }
    19 
    20         static Action CreateAction()
    21         {
    22             int value = 0;
    23             Action action = () => Console.Write(value++);
    24             return action;
    25         }
    26     }
    27 }

      你觉得上面的代码会输出什么呢?我们一般会认为,由于静态方法有自己线程栈,value变量会在对应的栈上分配空间,所以一旦方法CreateAction执行完毕,CreateAction对应的线程栈被销毁,value变量也会随之消失...但是令人惊讶的是,第二次和第三次调用action委托的时候,value变量似乎依然保留这上次调用后的值。所以我们认为输出的结果是000。可是运行代码,输出的结果却是 012。
      奇怪吗?秘密就在于我们之前的那个假设上->value是真的分配在自己的线程栈上的吗?答案是否定的。事件上呢,编译器会为我们创建一个额外的类来存储变量。CreateAction拥有对该类的一个实例的引用,所以CreateAction可以访问到变量value。同时Action委托也有对该实例的引用。这样的话,除非Action委托和CreateAction方法同时被销毁的时候,变量value所在的实例才会被销毁。通过ILDASM,可以清楚的看到编译器所产生的类<>c_DisplayClass1。

       同时在CreateAction方法中可以找到对<>c_DisplayClass1的引用

      我想,如果用C#代码去表示的话,大概是这样的

    View Code
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace TestLambda
     8 {
     9     class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13             Action action = CreateAction();
    14             action();
    15             action();
    16             action();
    17 
    18             var a = DynamicCreateAction();
    19             a();
    20             a();
    21             a();
    22 
    23             Console.Read();
    24         }
    25 
    26         static Action CreateAction()
    27         {
    28             int value = 0;
    29             Action action = () => Console.Write(value++);
    30             return action;
    31         }
    32 
    33         static Action DynamicCreateAction()
    34         {
    35             DisplayClass d = new DisplayClass();
    36 
    37             Action action = new Action(d.Print);
    38             return action;
    39         }
    40 
    41         class DisplayClass
    42         {
    43             public int Value { get; set; }
    44 
    45             public void Print()
    46             {
    47                 Console.Write(Value++);
    48             }
    49         }
    50 
    51     }
    52 
    53 }

      OK,我想你现在明白了,"局部变量“不一定是局部的了吧。

  • 相关阅读:
    vuex之store拆分即多模块状态管理
    vue项目中使用vueX
    vue中父子组件的参数传递和应用
    VUE中使用vue-awesome-swiper
    VUE真实项目中常用的生命周期和参数
    VUE生命周期
    vue+mockjs 模拟数据,请求回调的应用
    Vue项目搭建与部署还有调试插件Vue.js devtools
    tableTD中添加对角斜线
    前端面试题及答案,理论知识
  • 原文地址:https://www.cnblogs.com/LoveJerryZhang/p/2798159.html
Copyright © 2011-2022 走看看