本文介绍了捕获闭包(循环变量)在C#5.0的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这工作正常(意味着预期)在C#5.0:

  var actions = new List< Action> 
foreach(var i in Enumerable.Range(0,10))
{
actions.Add(()=> Console.WriteLine(i));
}
foreach(var act in actions)act();

打印0到9.但是这10次显示10次:

  var actions = new List< Action>(); 
for(var i = 0; i {
actions.Add(()=> Console.WriteLine(i));
}
foreach(var act in actions)act();问题:这是我们在C#5.0之前版本中遇到的问题;所以我们不得不使用闭包的循环局部占位符,它现在是固定的 - 在C#5.0 - 在foreach循环。但不是在for循环!



这里的原因是什么(不修复 for

解决方案

我会假设你的意思是为什么不改变循环?



答案是对于 for 循环,现有的行为是完全有道理的。如果你打破循环:




  • 初始化

  • 条件

  • 迭代器

  • 正文



...那么循环大致是:

  {
initializer;
while(condition)
{
body;
iterator;
}
}

continue; 语句结束时执行。)



初始化部分逻辑只发生一次,因此只有一个可变实例化是完全合乎逻辑的。此外,在循环的每次迭代中,变量没有自然的初始值 - 没有什么可说的 for 循环在初始化器中声明一个变量,在条件中测试它并在迭代器中修改它。您期望这样的循环是什么:

  for(int i = 0,j = 10; i  {
if(someCondition)
{
j ++;
}
actions.Add(()=> Console.WriteLine(i,j));
}

foreach 循环,就像你为每次迭代都声明一个单独的变量一样。 heck,变量是只读的,使它甚至更多奇怪的是,它是一个变量,在迭代之间变化。认为 foreach 循环在每次迭代时声明一个新的只读变量,其值取自迭代器,这是非常有意义的。


This works fine (means as expected) in C# 5.0:

var actions = new List<Action>();
foreach (var i in Enumerable.Range(0, 10))
{
    actions.Add(() => Console.WriteLine(i));
}
foreach (var act in actions) act();

Prints 0 to 9. But this one shows 10 for 10 times:

var actions = new List<Action>();
for (var i = 0; i < 10; i++)
{
    actions.Add(() => Console.WriteLine(i));
}
foreach (var act in actions) act();

Question: This was a problem that we had in C# versions before 5.0; so we had to use a loop-local placeholder for the closure and it's fixed now - in C# 5.0 - in "foreach" loops. But not in "for" loops!

What is the reasoning behind this (not fixing the problem for for loops too)?

解决方案

I'm going to assume you mean "why wasn't it changed for for loops as well?"

The answer is that for for loops, the existing behaviour makes perfect sense. If you break a for loop into:

  • initializer
  • condition
  • iterator
  • body

... then the loop is roughly:

{
    initializer;
    while (condition)
    {
        body;
        iterator;
    }
}

(Except that the iterator is executed at the end of a continue; statement as well, of course.)

The initialization part logically only happens once, so it's entirely logical that there's only one "variable instantiation". Furthermore, there's no natural "initial" value of the variable on each iteration of the loop - there's nothing to say that a for loop has to be of a form declaring a variable in the initializer, testing it in the condition and modifying it in the iterator. What would you expect a loop like this to do:

for (int i = 0, j = 10; i < j; i++)
{
    if (someCondition)
    {
        j++;
    }
    actions.Add(() => Console.WriteLine(i, j));
}

Compare that with a foreach loop which looks like you're declaring a separate variable for every iteration. Heck, the variable is read-only, making it even more odd to think of it being one variable which changes between iterations. It makes perfect sense to think of a foreach loop as declaring a new read-only variable on each iteration with its value taken from the iterator.

这篇关于捕获闭包(循环变量)在C#5.0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-16 06:51