在封警告访问的foreach变量 [英] Access to foreach variable in closure warning

查看:266
本文介绍了在封警告访问的foreach变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我收到以下警告:

  

进入到封闭的foreach变量。当使用不同版本的编译器编译可能有不同的行为。

这是它看起来像在我的编辑:

我知道如何解决这个问题的警告,但我想知道我为什么会得到这样的警告?

这是对CLR的版本?这是否与IL?

解决方案

有两个部分此警告。第一个是...

  

在关闭访问的foreach变量

...这不是无效的本身,而是它是违反直觉的第一眼。这也是很难做到的权利。 (正因如此,我的文章链接到下面介绍这是有害的。)

把你的查询,并指出,code你摘录基本上是一个C#编译器的扩展形式(前C#5)生成的foreach < SUP> 1 :

  

我[不​​]明白为什么[以下是]无效的:

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

嗯,这是有效的语法。如果你正在做在你的循环使用的那么一切都是美好的。但关闭了取值将导致反直觉的行为。看看下面的code:

  VAR countingActions =新的名单,其中,作用&gt;();

变种号码从中n = Enumerable.Range(1,5)
              选择n.ToString(CultureInfo.InvariantCulture);

使用(VAR枚举= numbers.GetEnumerator())
{
    字符串s;

    而(enumerator.MoveNext())
    {
        S = enumerator.Current;

        Console.WriteLine(创建行动,其中s == {0},S);
        动作动作=()=&GT; Console.WriteLine(S == {0},S);

        countingActions.Add(动作);
    }
}
 

如果您运行此code,你会得到下面的控制台输出:

 创建一个动作,其中S == 1
创建一个动作,其中s = = 2
创建一个动作,其中s = = 3
创建一个动作,其中S = = 4
创建一个动作,其中s = = 5
 

这是你所期望的。

要看到的东西,你可能不会想到,运行以下code的后,立即的上述code:

 的foreach(在countingActions VAR行动)
    行动();
 

您会得到以下控制台输出:

 取值== 5
小号== 5
小号== 5
小号== 5
小号== 5
 

为什么呢?因为我们创建了五个函数都做同样的事情:打印取值(我们已经关闭了)的值。在现实中,它们是相同的功能(打印取值,打印取值,打印<$ C $ç>取值......)。

目前的点,我们去使用他们,他们做什么,我们要问:打印的值S 。如果你看看的最后一个已知值S ,你会看到它的 5 。所以,我们得到取值== 5 印刷五次到控制台。

这正是我们要求,但可能不是我们想要的。

警告的第二部分...

  

在使用不同版本的编译器编译可能有不同的行为。

...就是这样。 <一href="http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx">Starting用C#5,编译器会生成不同的code表示prevents这从通过的foreach 发生。

因此​​,下面的code下会产生不同版本的编译器不同的结果:

 的foreach(VAR N的数字)
{
    动作动作=()=&GT; Console.WriteLine(N == {0},N);
    countingActions.Add(动作);
}
 

因此​​,也将产生R·警告:)

我的第一个code段,上面会出现相同的行为在所有版本的编译器,因为我没有使用的foreach (更确切地说,我已经扩大了它的出路preC#5编译器做的)。

  

这是对CLR版本?

我不太清楚你问这里。

埃里克利珀的帖子说这种改变发生在C#5。所以presumably你必须面向.NET 4.5或更高版本与C#5或更高版本的编译器,以获得新的行为,一切都在那之前得到旧的行为。

但要清楚,这是编译器的.NET Framework版本的函数,而不是。

  

有没有关联性与IL?

不同code会产生不同的IL因此在这个意义上有生成的IL后果。

1 的foreach 是一个更常见的结构比code您已经张贴在您的评论。这个问题通常出现通过使用的foreach ,而不是通过手工枚举。这就是为什么在C#中的变为的foreach 5帮助prevent这个问题,但不完全。

I'm getting the following warning:

Access to foreach variable in closure. May have different behaviour when compiled with different versions of compiler.

This is what it looks like in my editor:

I know how fix this warning, but I want know why would I get this warning?

Is this about the "CLR" version? Is it related to "IL"?

解决方案

There are two parts to this warning. The first is...

Access to foreach variable in closure

...which is not invalid per se but it is counter-intuitive at first glance. It's also very hard to do right. (So much so that the article I link to below describes this as "harmful".)

Take your query, noting that the code you've excerpted is basically an expanded form of what the C# compiler (before C# 5) generates for foreach1:

I [don't] understand why [the following is] not valid:

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

Well, it is valid syntactically. And if all you're doing in your loop is using the value of s then everything is good. But closing over s will lead to counter-intuitive behaviour. Take a look at the following code:

var countingActions = new List<Action>();

var numbers = from n in Enumerable.Range(1, 5)
              select n.ToString(CultureInfo.InvariantCulture);

using (var enumerator = numbers.GetEnumerator())
{
    string s;

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

        Console.WriteLine("Creating an action where s == {0}", s);
        Action action = () => Console.WriteLine("s == {0}", s);

        countingActions.Add(action);
    }
}

If you run this code, you'll get the following console output:

Creating an action where s == 1
Creating an action where s == 2
Creating an action where s == 3
Creating an action where s == 4
Creating an action where s == 5

This is what you expect.

To see something you probably don't expect, run the following code immediately after the above code:

foreach (var action in countingActions)
    action();

You'll get the following console output:

s == 5
s == 5
s == 5
s == 5
s == 5

Why? Because we created five functions that all do the exact same thing: print the value of s (which we've closed over). In reality, they're the same function ("Print s", "Print s", "Print s"...).

At the point at which we go to use them, they do exactly what we ask: print the value of s. If you look at the last known value of s, you'll see that it's 5. So we get s == 5 printed five times to the console.

Which is exactly what we asked for, but probably not what we want.

The second part of the warning...

May have different behaviour when compiled with different versions of compiler.

...is what it is. Starting with C# 5, the compiler generates different code that "prevents" this from happening via foreach.

Thus the following code will produce different results under different versions of the compiler:

foreach (var n in numbers)
{
    Action action = () => Console.WriteLine("n == {0}", n);
    countingActions.Add(action);
}

Consequently, it will also produce the R# warning :)

My first code snippet, above, will exhibit the same behaviour in all versions of the compiler, since I'm not using foreach (rather, I've expanded it out the way pre-C# 5 compilers do).

Is this for CLR version?

I'm not quite sure what you're asking here.

Eric Lippert's post says the change happens "in C# 5". So presumably you have to target .NET 4.5 or later with a C# 5 or later compiler to get the new behaviour, and everything before that gets the old behaviour.

But to be clear, it's a function of the compiler and not the .NET Framework version.

Is there relevance with IL?

Different code produces different IL so in that sense there's consequences for the IL generated.

1 foreach is a much more common construct than the code you've posted in your comment. The issue typically arises through use of foreach, not through manual enumeration. That's why the changes to foreach in C# 5 help prevent this issue, but not completely.

这篇关于在封警告访问的foreach变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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