zoukankan      html  css  js  c++  java
  • 匿名方法

    与前面的可空类型是一样的,匿名方法也是C# 2.0里面提出来的。

    1 匿名方法

       1.1 什么是匿名方法?

            顾名思义,就是没有名称的方法,因为没有名称,匿名方法只能在函数定义(匿名方法是把方法的实现和定义嵌套在了一起)的时候被调用,在其他任何情况下都不能被调用。对于编译器来说,匿名方法并不是没有名字的,编译器在编译匿名方法时会为其生成一个方法名,下面可以通过IL代码来证明。

       

     1 namespace 匿名方法
     2 {
     3     class Program
     4     {
     5         private delegate void VoteDelegate(string name);
     6         static void Main(string[] args)
     7         {
     8             //使用匿名方法来实例化委托对象
     9             VoteDelegate voteDelegate = delegate(string name)
    10             {
    11                 Console.WriteLine("昵称为:{0} 来帮我提高啦",name);
    12             };
    13             //通过调用委托来回调Vote方法,这是隐式调用方式
    14             voteDelegate("Hong");
    15             Console.ReadKey();
    16         }
    17     }
    18 }

        从以上的代码可以看出,委托对象可用匿名方法来实例化的。当并不能一概而论,匿名方法也有它本身的缺点——不能在其他地方被调用,即不具有复用性。而且,匿名方法会自动形成“闭包”。当一个函数(这里成为外部函数)包含对另一个函数(内部函数)的调用时,或当内部函数使用了外部函数的变量时,都会形成闭包。闭包可能会延长外部变量的生命周期。所以如果委托包装的方法相对简单,并且该方法在其他地方的调用频率较低,你就可以考虑用匿名方法来实例化委托对象。

        

        1.2 对变量捕捉过程的剖析

             变量被匿名方法捕获后,变量的生命周期会被延长,就是说对于一个被捕获的变量而言,只要还有任何委托实例在引用它,它就一直存在,就不会在部分委托实例调用结束后被垃圾回收释放掉。下面通过代码来解释:

     1 class Program
     2     {
     3         private delegate void ClosureDelegate();
     4         static void Main(string[] args)
     5         {
     6             ClosureDelegate test = CreateDelegateInstance();
     7             test();
     8             Console.ReadKey();
     9         }
    10 
    11         private static ClosureDelegate CreateDelegateInstance()
    12         {
    13             //外部变量
    14             int count = 1;
    15             ClosureDelegate closureDelegate = delegate()
    16             {
    17                 Console.WriteLine(count);
    18                 count++;
    19             };
    20             closureDelegate();
    21             return closureDelegate;
    22         }
    23     }

    结果:

        我并不知道大家对这个结果是否感到惊讶,第一次输出1是正常的,但第二个输出2确实比较奇妙的。大家可能会认为应该抛出异常才对,因为count在栈上的生命周期已经结束。但结果确实是输出2,是不会错的,我们可以倒推原因,使用匿名方法时,编译器会创建一个额外的类来容纳变量,此时count变量会被分配到堆上的。CreateDelegateInstance方法有该类的一个实例引用,所以此时匿名方法捕捉到的是变量count的一个引用,而不是真真的值。在这个过程中,匿名方法延长了变量count的生命周期。

        对于匿名方法捕捉到的变量,编译器会额外创建一个类来容纳它们。

        

        由上图可知,我们并没有在源码中定义<>c_DisplayClass2_0类。这个类就是编译器创建来容纳捕获的变量count的,该类还容纳了CreateDelegateInstance的方法。

  • 相关阅读:
    Golang结构体序列化与反序列化时默认值的问题
    Golang在函数中给结构体对象赋值的一个坑
    Go出现panic的场景
    Redis内存使用率增长的一些解决思路
    「转」50个Go新手容易犯的错误
    关系型数据库跨时区查询简介
    Golang中append与copy内置函数介绍
    实践案例1利用低代码开发平台Odoo快速构建律师事务所管理系统
    自助分析工具Power BI的简介和应用
    一个开源免费高颜值的轻量级商业智能BI平台Superset 介绍
  • 原文地址:https://www.cnblogs.com/Helius/p/5751435.html
Copyright © 2011-2022 走看看