LAMBDA捕获问题迭代器? [英] Lambda capture problem with iterators?

查看:166
本文介绍了LAMBDA捕获问题迭代器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

道歉,如果这个问题已经被问过,但假设我们有这样的代码(我使用Mono 2.10.2运行它,并与的GMC编译 2.10.2.0)

Apologies if this question has been asked already, but suppose we have this code (I've run it with Mono 2.10.2 and compiled with gmcs 2.10.2.0):

using System;

public class App {
    public static void Main(string[] args) {
        Func<string> f = null;
        var strs = new string[]{
            "foo",
            "bar",
            "zar"
        };

        foreach (var str in strs) {
            if ("foo".Equals(str)) 
                f = () => str;
        }
        Console.WriteLine(f());     // [1]: Prints 'zar'

        foreach (var str in strs) {
            var localStr = str;
            if ("foo".Equals(str))
                f = () => localStr;
        }
        Console.WriteLine(f());     // [2]: Prints 'foo'

        { int i = 0;
        for (string str; i < strs.Length; ++i) {
            str = strs[i];
            if ("foo".Equals(str)) 
                f = () => str;
        }}
        Console.WriteLine(f());     // [3]: Prints 'zar'
    }
}



据逻辑上似乎 [1] 打印相同的 [3] 。但说实话,我有点希望它打印相同的 [2] 。我莫名其妙地相信的实施[1] 将接近 [2]

It seems logical that [1] print the same as [3]. But to be honest, I somehow expected it to print the same as [2]. I somehow believed the implementation of [1] would be closer to [2].

:任何人都可以请提供到它告诉究竟是如何 STR 变量(或者规范的引用即使迭代器)由拉姆达在捕捉[1]

Question: Could anyone please provide a reference to the specification where it tells exactly how the str variable (or perhaps even the iterator) is captured by the lambda in [1].

我想我所寻找的是确切的实施的foreach 循环。

I guess what I am looking for is the exact implementation of the foreach loop.

推荐答案

您问了参考说明书;相关位置是部分8.8.4,其中规定了foreach循环相当于:

You asked for a reference to the specification; the relevant location is section 8.8.4, which states that a "foreach" loop is equivalent to:

    V v;
    while (e.MoveNext()) {
        v = (V)(T)e.Current;
        embedded-statement
    }

请注意,该值V之外声明而循环,因此,有一个单独的循环变量。然后由拉姆达关闭了。

Note that the value v is declared outside the while loop, and therefore there is a single loop variable. That is then closed over by the lambda.

因为这么多的人碰上这种问题C#设计和编译器团队改变了C#5有这些语义

    while (e.MoveNext()) {
        V v = (V)(T)e.Current;
        embedded-statement
    }



而后者则具有预期的行为 - 你每次收过不同的变量。从技术上讲这是一个重大更改,但谁取决于您所遇到的怪异行为的人数是希望非常小。

Which then has the expected behaviour -- you close over a different variable every time. Technically that is a breaking change, but the number of people who depend on the weird behaviour you are experiencing is hopefully very small.

注意,C#2,3和4,现在用在这方面的C#5不相容。还要注意,更改仅适用于的foreach ,而不是循环。

Be aware that C# 2, 3, and 4 are now incompatible with C# 5 in this regard. Also note that the change only applies to foreach, not to for loops.

请参阅的 http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/ 了解详情。

批评家abergmeier状态:

Commenter abergmeier states:

C#是具有这种唯一的语言奇怪的行为。

C# is the only language that has this strange behavior.

这种说法是错误的断然。考虑下面的JavaScript:

This statement is categorically false. Consider the following JavaScript:

var funcs = [];
var results = [];
for(prop in { a : 10, b : 20 })
{
  funcs.push(function() { return prop; });
  results.push(funcs[0]());
}



abergmeier,你会关心采取猜测,是什么内容结果

这篇关于LAMBDA捕获问题迭代器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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