为什么此for迭代变量在for循环之后仍然存在?

时间:2018-12-29 21:53:41

标签: c#

我一直在阅读一些C#面试问题,并发现了一个流行的关于代表的问题的排列方式,使我感到困惑。

问题是:

  

预测以下代码的输出。

delegate void Iterator();

static void Main(string[] args)
{
    List<Iterator> iterators = new List<Iterator>();
    for (int i = 0; i < 15; i++)
    {
        iterators.Add(delegate { Console.WriteLine(i); });
    }

    foreach (var iterator in iterators)
    {
        iterator();
    }

    Console.Read();
}

我所见过的这个问题的普通版本在i循环之前声明for变量,从而使其在方法范围内,并且很容易看出为什么the output is "15" 15 times. < / p>

但是,当我调试代码时,i变量在foreach循环中超出范围,并且不再存在。但是,当我进入iterator()方法时,它存在于Console.WriteLine(i)行中。

我不明白。

2 个答案:

答案 0 :(得分:4)

编译器会将您的代码转换为以下代码,这就是i变量不超出范围的原因。

private delegate void Iterator();

[CompilerGenerated]
private sealed class CompGenCls
{
    public int i;

    internal void CompGenFunc()
    {
        Console.WriteLine(i);
    }
}

private static void Main(string[] args)
{
    List<Iterator> iterators = new List<Iterator>();
    CompGenCls obj = new CompGenCls();
    obj.i = 0;
    for (; obj.i < 15; obj.i++)
    {
        iterators.Add(obj.CompGenFunc);
    }

    foreach (Iterator item in iterators)
    {
        item();
    }
    Console.Read();
}

答案 1 :(得分:2)

  

简单地说,闭包允许您封装一些   行为,像其他任何对象一样传递它,并且仍然可以访问   到它们最初被声明的上下文。这使您能够   将控制结构,逻辑运算符等与   有关如何使用它们的详细信息。能够访问   原始上下文是将闭包与普通对象区分开来的,   尽管闭包实现通常使用正常   对象和编译器的诡计。

     

在您的示例中,您实际上仅声明了一个i变量-   以便所有Action实例都捕获相同的i变量。的   结果是每行上打印的数字为15。 o“修复”代码   以使其显示大多数人期望的输出(即0到14)   我们需要在循环中引入一个额外的变量:

delegate void Iterator();

static void Main(string[] args)
{
    List<Iterator> iterators = new List<Iterator>();
    for (int i = 0; i < 15; i++)
    {
        int copy = i;
        iterators.Add(delegate { Console.WriteLine(copy); });
    }

    foreach (var iterator in iterators)
    {
        iterator();
    }

    Console.Read();
}
  

每次我们经历循环时,都会被告知与众不同   copy变量的实例-每个操作捕获一个不同的变量   变量。如果您看一下编译器的   实际上是在幕后做的,但最初它会飞到脸上   大多数开发人员(包括我)的直觉。

via

相关问题