是否有一个foreach变量的C#的重用理由吗? [英] Is there a reason for C#'s reuse of the variable in a foreach?

查看:238
本文介绍了是否有一个foreach变量的C#的重用理由吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用lambda前pressions或C#匿名方法,我们必须要警惕的的进入修改封的陷阱。例如:

 的foreach(字符串中的变种S)
{
   查询= query.Where(ⅰ= GT; i.Prop == S); //获得修改关闭
   ...
}

由于修改后的关闭,上述code将导致所有的其中,条款的查询是基于<$ C $终值ç>取值。

由于这里解释,出现这种情况因为在的foreach 宣布上述循环被翻译这样的编译器中的取值变量:

 字符串s;
而(enumerator.MoveNext())
{
   S = enumerator.Current;
   ...
}

而不是这样的:

 而(enumerator.MoveNext())
{
   字符串s;
   S = enumerator.Current;
   ...
}

随着指出这里,没有性能优势声明外循环的变量,一般情况下只有我能这样做觉得原因是,如果你打算使用变量循环的范围:

 字符串s;
而(enumerator.MoveNext())
{
   S = enumerator.Current;
   ...
}
变种finalString =秒;

然而,在的foreach 循环中定义的变量不能在循环外使用:

 的foreach(字符串s中的字符串)
{
}
变种finalString =秒; //将不起作用:你的范围之内。

因此​​,编译器声明的方式,使得它非常容易,往往很难发现和调试错误的变量,同时产生没有明显的好处。

有什么你可以用的foreach DO循环这种方式,你不能,如果他们被编译的内部范围的变量,或者这只是一个任意选择那是在匿名方法和lambda前pressions是可利用的或共同制作,并且还没有被从那时起修改?


解决方案

  

,编译器声明的方式,使得它非常容易,往往很难发现和调试错误的变量,同时产生没有明显的好处。


您的批评是完全有道理的。

我在这里详细讨论这个问题:

<一个href=\"http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/\">Closing在循环变量被认为是有害


  

有什么你可以用foreach DO循环这种方式,你不能,如果他们有内部范围的变量编译?或者这恰好是之前匿名方法和lambda前pressions是可利用的或共同做成任意选择,而没有被从那时起修改?


后者。在C#1.0规范实际上不说循环变量是否是内部或循环体外面,因为它使无可见差异。当关闭语义引入C#2.0中,选择是为了把循环外循环变量,用for循环是一致的。

我认为这是公平地说,所有的后悔这一决定。这是在C#中最糟糕的陷阱之一,和我们将采取重大更改来修复它。在C#5 foreach循环变量将逻辑上的 的内部循环体,因此,警方将封闭每次都获得一个新的副本。

循环不会改变,并且改变将不会被向后移植到C#previous版本。因此,应继续使用这个成语时要小心。

When using lambda expressions or anonymous methods in C#, we have to be wary of the access to modified closure pitfall. For example:

foreach (var s in strings)
{
   query = query.Where(i => i.Prop == s); // access to modified closure
   ...
}

Due to the modified closure, the above code will cause all of the Where clauses on the query to be based on the final value of s.

As explained here, this happens because the s variable declared in foreach loop above is translated like this in the compiler:

string s;
while (enumerator.MoveNext())
{
   s = enumerator.Current;
   ...
}

instead of like this:

while (enumerator.MoveNext())
{
   string s;
   s = enumerator.Current;
   ...
}

As pointed out here, there are no performance advantages to declaring a variable outside the loop, and under normal circumstances the only reason I can think of for doing this is if you plan to use the variable outside the scope of the loop:

string s;
while (enumerator.MoveNext())
{
   s = enumerator.Current;
   ...
}
var finalString = s;

However variables defined in a foreach loop cannot be used outside the loop:

foreach(string s in strings)
{
}
var finalString = s; // won't work: you're outside the scope.

So the compiler declares the variable in a way that makes it highly prone to an error that is often difficult to find and debug, while producing no perceivable benefits.

Is there something you can do with foreach loops this way that you couldn't if they were compiled with an inner-scoped variable, or is this just an arbitrary choice that was made before anonymous methods and lambda expressions were available or common, and which hasn't been revised since then?

解决方案

The compiler declares the variable in a way that makes it highly prone to an error that is often difficult to find and debug, while producing no perceivable benefits.

Your criticism is entirely justified.

I discuss this problem in detail here:

Closing over the loop variable considered harmful

Is there something you can do with foreach loops this way that you couldn't if they were compiled with an inner-scoped variable? or is this just an arbitrary choice that was made before anonymous methods and lambda expressions were available or common, and which hasn't been revised since then?

The latter. The C# 1.0 specification actually did not say whether the loop variable was inside or outside the loop body, as it made no observable difference. When closure semantics were introduced in C# 2.0, the choice was made to put the loop variable outside the loop, consistent with the "for" loop.

I think it is fair to say that all regret that decision. This is one of the worst "gotchas" in C#, and we are going to take the breaking change to fix it. In C# 5 the foreach loop variable will be logically inside the body of the loop, and therefore closures will get a fresh copy every time.

The for loop will not be changed, and the change will not be "back ported" to previous versions of C#. You should therefore continue to be careful when using this idiom.

这篇关于是否有一个foreach变量的C#的重用理由吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆