zoukankan      html  css  js  c++  java
  • C#基础—匿名方法(Anonymous Mehod)

    1、引入匿名方法

        早在C# 2.0中就提出了匿名方法,实现了以一种内联的方式声明委托,在此之前,声明委托唯一的方法是"命名方法",虽然 C# 3.0 里有了lambda ,使得写内联代码更加简洁和方法,但是匿名方法依然有他的用处,匿名方法提供了可以忽略参数列表的能力。

    2、匿名方法的使用和注意点

        什么匿名方法?简单的理解就是没有定义名字的方法(其实编译器还是帮我们生成了一个方法)。代码的实现就是把方法的定义和方法的实现内联到了一起。

        先看个演示例子:

     1 class Program
     2 {
     3     static void Main(string[] args)
     4     {
     5         Thread t1 = new Thread(printMethod);
     6         t1.Start();
     7 
     8         Console.Read();
     9     }
    10 
    11     static void printMethod()
    12     {
    13         Console.WriteLine("Start Thread");
    14     }
    15 
    16 }

      如果使用匿名方法,就是把方法定义和方法实现内联到一起,避免重新定义命名方法,看Demo:

     1 class Program
     2 {    
     3         static void Main(string[] args)
     4         {
     5               Thread t1 = new Thread(delegate()
     6                       {
     7                             Console.WriteLine("Thread Start");
     8                       });
     9 
    10                t1.Start();
    11 
    12                Console.Read();
    13        }
    14 }                    

        这是一个简单使用匿名方法内联委托实例的例子,在使用匿名方法时,有一些注意点如下:

       (1)、匿名方法中,外部变量的引用被称为"捕获的外部变量",与本地变量不同,捕获的变量的生存期被扩展或延长,直到引用该匿名方法委托被垃圾回收。

       (2)、匿名方法不能访问外部范围的 ref 或 out 参数。

       (3)、在"匿名方法块"中不能访问任何不安全代码,即不能使用指针。

       (4)、在 is 运算符的左侧不允许使用匿名方法。

        这里,需要特别提下的是,匿名方法中的外部变量问题,在使用匿名方法时会形成闭包(closure),与javascript 中的闭包类似。

        先看下演示的例子:

     1 public delegate void DelegateDemo();
     2 
     3 class Program
     4 {
     5     static void Main(string[] args)
     6     {
     7         DelegateDemo d = TestCaptureVariable();
     8         d(); //再次调用
     9 
    10         Console.Read();
    11     }
    12 
    13     static DelegateDemo TestCaptureVariable()
    14     {
    15         //被捕获的外部变量(就是在匿名方法中引用到的变量)
    16         int captureVariable = 100;
    17         int variable = 101;
    18         DelegateDemo d = delegate()
    19         {
    20             Console.WriteLine(captureVariable);
    21             captureVariable = 200;
    22         };
    23 
    24         d(); //声明完后直接调用
    25         return d;
    26     }
    28 }            

    程序输出:

    100

    200

         在本示例程序中,定义了值类型变量captureVariable ,定义在栈上,当第一次调用d(),并结束执行TestCaptureVariable方法后,captureVariable 和 variable 应该被GC回收了,但我们第一次调用d()时,仍然输出了200。

        这种效果就是第一点所说的"捕获变量"的生存周期会因为引用一直存在而被延长。对此,我们可以看下编译器为此做了些什么:

        在Program类中多了一个系统自动命名的类,DisplayClass1,这个类里,包含了 captureVariable,其实,编译器对captureVariable,这个匿名方法中的"被捕获变量" 做了一个特别的处理,自动生成了一个类,这个类中包含了该变量,而匿名方法一直保留了对这个类的引用,所以没有被GC回收,所以除了栈上,在其他地方也保存了这个变量,从而导致这个变量并没有被销毁,从而达到了"延长生命周期"的目的。

  • 相关阅读:
    ThinkPHP 3.2.2 实现持久登录 ( 记住我 )
    Java实现 LeetCode 20 有效的括号
    Java实现 LeetCode 20 有效的括号
    Java实现 LeetCode 19删除链表的倒数第N个节点
    Java实现 LeetCode 19删除链表的倒数第N个节点
    Java实现 LeetCode 19删除链表的倒数第N个节点
    Java实现 LeetCode 18 四数之和
    Java实现 LeetCode 18 四数之和
    Java实现 LeetCode 18 四数之和
    Java实现 LeetCode 17 电话号码的字母组合
  • 原文地址:https://www.cnblogs.com/ydchw/p/3735517.html
Copyright © 2011-2022 走看看