美文网首页
C#闭包陷阱

C#闭包陷阱

作者: 祝你万事顺利 | 来源:发表于2019-05-31 14:46 被阅读0次

在C#中,lambda(匿名委托)使用时,编译器会自动生成一个类来保存lambda中的方法以及字段,当lambda引用外部变量的时候,编译器会在生成的类中创建一个字段保存引用到的变量。
在for循环定义的循环变量是for块级别的,没有在循环迭代时候创建新的变量。也就是说想在for循环中的lambda执行的时候调用外部变量将只能获取最新的值,所以我们需要在for循环中创建一个临时变量这样lambda将这个临时变量的值存起来。

用例:

class Program
    {
        static void Main(string[] args)
        {
            List<Person> li = new List<Person>()
            {
                new Person("kk"),
                new Person("cc"),
            };
            Action[] array = new Action[2];
            for (int i = 0; i < 2; i++)
            {
                array[i] = () => { Console.WriteLine(li[i].name);};
            }
            for (int i = 0; i < 2; i++)
            {
                array[i]();
            }
        }
    }
    public class Person
    {
        public string name;

        public Person()
        {
        }

        public Person(string name)
        {
            this.name = name;
        }
    }

反编译
反编译可以看到在Main中有一个<>c__DisplayClass0_2.i,此变量会在复制后变为赋值时循环的次数加一

private static void Main(string[] args)
        {
            Program.<>c__DisplayClass0_0 <>c__DisplayClass0_ = new Program.<>c__DisplayClass0_0();
            <>c__DisplayClass0_.li = new List<Person>
            {
                new Person("kk"),
                new Person("cc")
            };
            Action[] array = new Action[2];
            Program.<>c__DisplayClass0_1 <>c__DisplayClass0_2 = new Program.<>c__DisplayClass0_1();
            <>c__DisplayClass0_2.CS$<>8__locals1 = <>c__DisplayClass0_;
            <>c__DisplayClass0_2.i = 0;
            while (<>c__DisplayClass0_2.i < 2)
            {
                array[<>c__DisplayClass0_2.i] = new Action(<>c__DisplayClass0_2.<Main>b__0);
                int i = <>c__DisplayClass0_2.i;
                <>c__DisplayClass0_2.i = i + 1;
            }
            for (int j = 0; j < 2; j++)
            {
                array[j]();
            }
        }

修改后:

static void Main(string[] args)
        {
            List<Person> li = new List<Person>()
            {
                new Person("kk"),
                new Person("cc"),
            };
            Action[] array = new Action[2];
            for (int i = 0; i < 2; i++)
            {
                int index = i;
                array[index] = () => { Console.WriteLine(li[index].name);};
            }
            for (int i = 0; i < 2; i++)
            {
                array[i]();
            }
        }

反编译:

private static void Main(string[] args)
        {
            Program.<>c__DisplayClass0_0 <>c__DisplayClass0_ = new Program.<>c__DisplayClass0_0();
            <>c__DisplayClass0_.li = new List<Person>
            {
                new Person("kk"),
                new Person("cc")
            };
            Action[] array = new Action[2];
            for (int i = 0; i < 2; i++)
            {
                Program.<>c__DisplayClass0_1 <>c__DisplayClass0_2 = new Program.<>c__DisplayClass0_1();
                <>c__DisplayClass0_2.CS$<>8__locals1 = <>c__DisplayClass0_;
                <>c__DisplayClass0_2.index = i;
                array[<>c__DisplayClass0_2.index] = new Action(<>c__DisplayClass0_2.<Main>b__0);
            }
            for (int j = 0; j < 2; j++)
            {
                array[j]();
            }
        }

相关文章

  • C#闭包陷阱

    在C#中,lambda(匿名委托)使用时,编译器会自动生成一个类来保存lambda中的方法以及字段,当lambda...

  • C# 闭包

    闭包的概念 内层的函数可以引用包含在它外层的函数的变量,即使外层函数的执行已经终止。但该变量提供的值并非变量创建时...

  • useEffect 闭包陷阱

    使用 useEffect 比较容易出现问题是闭包陷阱,尽量尝试不使用 useEffect,见第4。 1. 错误演示...

  • swift-闭包

    闭包 闭包定义 闭包简化 - 尾随闭包 闭包参数 闭包返回值 闭包的循环引用

  • react hook 的闭包陷阱

    上一篇文章 https://www.jianshu.com/p/272c7d36021a[https://www....

  • 闭包,闭包,闭包

    1、这家伙到底是什么? 网上关于这个的讨论的太多了太多了,有各种的举例子,但是大部分还在寻找这个答案的小伙伴对于变...

  • 闭包-Closures [swift 5.1]

    闭包的语法 尾随闭包 闭包逃离 自动闭包

  • Day7 闭包(Closures)

    本页包含内容:• 闭包表达式• 尾随闭包• 值捕获• 闭包是引用类型• 逃逸闭包• 自动闭包 1、闭包表达式 闭包...

  • Python闭包

    闭包 = 环境变量 + 函数 调用闭包内部的环境变量 闭包的经典误区 闭包与非闭包实现人类走路 非闭包 闭包

  • 闭包(closure)

    ● 闭包基础 ● 闭包作用 ● 闭包经典例子 ● 闭包应用 ● 闭包缺点 ● 参考资料 1、闭包基础 作用域和作...

网友评论

      本文标题:C#闭包陷阱

      本文链接:https://www.haomeiwen.com/subject/txwwtctx.html