【问题标题】:.NET IEnumerator<string> not advancing on MoveNext when in yield block.NET IEnumerator<string> 在 yield 块中不前进 MoveNext
【发布时间】:2011-11-04 16:08:23
【问题描述】:

下面的代码(用于在 LinqPad 中运行)旨在将“foo/skip/bar”字符串解析为项目对象,跳过“跳过”位,为“foo”和“bar”生成项目对象。运行时,会产生 2 个“条形”项目。

在 TryGetChild 方法中,当找到“skip”时,将枚举数从“skip”向前移动到“bar”。但是,当执行返回到调用方法时,枚举器又回到“跳过”状态。

我认为这是一些 yield 块怪异,好像我在 Main() 中进行拆分并将枚举器传递给 Walk() 它可以正常工作。有人可以解释枚举器是如何返回的吗?是否正在创建一个新的?

edit:这是我在代码中发现的看似奇怪的情况的一个非常简化的版本。我是出于好奇而提出这个问题,而不是寻找我已经找到的解决方法。

/* output from program

enumerator moved to foo
enumerator moved to skip
enumerator moved to bar
enumerator moved to bar

Item [] (3 items)  

foo
bar     
bar
*/     


static void Main()
{
    Walk("foo/skip/bar").ToArray().Dump();
}

private static IEnumerable<Item> Walk(string pathString)
{
    var enumerator = pathString.Split('/').ToList().GetEnumerator();
    var current = new Item() { S = "" };
    while (enumerator.MoveNext())
    {
        Console.WriteLine("enumerator moved to " + enumerator.Current);
        yield return current.TryGetChild(enumerator);
    }
}
class Item
{
    public string S { get; set; }

    public Item TryGetChild(IEnumerator<string> enumerator)
    {
        if (enumerator.Current == "skip")
        {
            enumerator.MoveNext(); //iterator moves on to 123
            Console.WriteLine("enumerator moved to " + enumerator.Current);
        }
        return new Item() { S = enumerator.Current };
    }
}

【问题讨论】:

  • 您的代码是否有理由需要使用此方法?您的目标似乎可以通过更简单的方式实现。

标签: .net yield-return


【解决方案1】:

您看到这种行为的原因是List&lt;T&gt;.GetEnumerator() 返回了List&lt;T&gt;.Enumerator 的一个实例,它是一个结构。因此,您将值类型传递给 TryGetChild() 方法,并且该类型的任何突变(包括由 MoveNext() 完成的突变)将不会反映在调用者中。

【讨论】:

  • 该死,我也得出了这个结论(虽然不是通过查看 IL,只是按照您在最后一句中的建议进行操作。这是一个很好的陷阱......
  • @Chris 是,不是。总的来说很高兴知道,但依赖于传递一个枚举器无论如何都是在自找麻烦。
  • 是的,我确实考虑在我的评论中添加“以及我永远不会使用枚举器的另一个原因”。乍一看似乎很安全...... :)
  • @Chris 是的,我花了一分钟才意识到发生了什么。 “嗯,应该反映变化,因为他正在传递参考。等等……他是……啊哈!”
  • @mcintyre321:不,var 与它无关。如果将其设为显式类型声明,则会得到完全相同的行为。要绕过该错误,您需要将迭代器作为参考传递。基本上它与如何传递引用和值类型有关。 yoda.arachsys.com/csharp/parameters.html 是一篇很棒的文章,可能有助于解释这种行为。
【解决方案2】:

我认为yield 仅在使用IEnumerableIEnumerable&lt;T&gt; 循环时有效。

【讨论】:

  • 您能否澄清一下“仅有效”的含义...如果他不尝试以单独的方法推进迭代器,那肯定可以正常工作...
  • yield 绝对不是问题。请参阅我的答案以了解实际情况。
猜你喜欢
  • 2014-09-05
  • 2023-03-21
  • 2010-10-22
  • 1970-01-01
  • 2019-06-19
  • 1970-01-01
  • 2014-06-27
  • 2016-06-21
  • 2011-03-10
相关资源
最近更新 更多