闭包

/// <summary>
/// 闭包
/// 1、函数嵌套,一个函数内部有另一个函数,并且内部函数有外部函数的局部变量
/// 2、闭包会捕获周围环境的自由变量(局部变量)
/// 3、闭包会将内部函数作为返回值返回,供外部函数调用
/// </summary>
public class Demo3
{
    /// <summary>
    /// 在这个方法中lambda表达式有延迟
    /// 它捕获的是变量的引用,而不是创建时候的变量
    /// 结束后的2
    /// </summary>
    /// <param name="count"></param>
    /// <returns></returns>
    public Action<int>[] CreateAction(int count=3)
    {
        var action = new Action<int>[count];
        for (int i = 0; i < count; i++)
        {         
            Console.WriteLine("-------开始------");
            action[i] = x => Console.WriteLine(x * i);
            Console.WriteLine("--------结束------");


           /* Console.WriteLine("-------开始------");
            int j = i;
            action[i] = x => Console.WriteLine(x * j);
            Console.WriteLine("--------结束------");*/

        }
        return action;
    }
    public void GetAction()
    {
        var action = CreateAction();
        action[0].Invoke(10);
        action[1].Invoke(10);
        action[2].Invoke(10);
    }

    /// <summary>
    /// 使用string能更好的看出来,lambda是调的引用
    /// 垃圾回收是追踪和释放不被程序使用的内存对象
    /// 而闭包没有被程序调用的时候,也是垃圾,是会被回收的。
    /// 但是有一点,闭包引用的自由变量也就是局部变量,是其他代码的引用
    /// 所以只要有一个活跃的引用,闭包不会被回收,而导致内存泄漏
    /// 为了避免这种情况,应该在合理的时候,手动订阅事件,取消闭包,回收垃圾
    /// </summary>
    /// <param name="count"></param>
    /// <returns></returns>
    public Action<string>[] CreateActionString(int count = 3)
    {
        var action = new Action<string>[count];
        for (int i = 0; i < count; i++)
        {
            action[i] = x => Console.WriteLine(x+"开始");
        }
        return action;
    }
    public void GetActionString()
    {
        var action = CreateActionString();
        action[0].Invoke("10");
        action[1].Invoke("10");
        action[2]("10");
        Console.ReadLine();
    }
}

使用引用类型,故意报错,可查看闭包的调用情况

 public class Demo5
 {
     /* public static Action<int>[] CreateAction(int count = 3)
      {
          var action = new Action<int>[count];
          var multipliers = new int[count]; // 创建一个数组来存储乘数

          // 初始化 multipliers 数组的值
          for (int i = 0; i < count; i++)
          {
              multipliers[i] = i;
          }

          // 为每个行动创建一个委托
          for (int i = 0; i < count; i++)
          {
              // 闭包捕获 multipliers 数组中的特定元素
              action[i] = x => Console.WriteLine(x * multipliers[i]);
          }

          return action;
      }*/

     /// <summary>
     /// 这两种方法都会报错,循环结束后的值是3
     /// </summary>
     /// <param name="count"></param>
     /// <returns></returns>
     public static Action<int>[] CreateAction(int count = 3)
     {
         var action = new Action<int>[count];
         var multipliers = new Dictionary<int, int>(); // 创建一个字典来存储乘数

         // 填充字典与乘数
         for (int i = 0; i < count; i++)
         {
             multipliers[i] = i;
         }
         var str1=multipliers.Keys.ToArray();
         var str2=multipliers.Values.ToArray();
         // 为每个行动创建一个委托
         for (int i = 0; i < count; i++)
         {
             // 闭包捕获字典中的特定键
             action[i] = x => Console.WriteLine(x * multipliers[i]);
         }

         return action;
     }
     public static void GetAction()
     {
         var action = CreateAction();
         action[0].Invoke(10);
         action[1].Invoke(10);
         action[2].Invoke(10);
     }
 }

本文作者:孤沉

本文链接:https://www.cnblogs.com/guchen33/p/18084187

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   孤沉  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开