【问题标题】:How does foreach work when looping through function results?循环遍历函数结果时,foreach 是如何工作的?
【发布时间】:2009-10-27 18:36:40
【问题描述】:

假设我有以下代码:

foreach(string str in someObj.GetMyStrings())
{
    // do some stuff
}

循环的每次迭代都会调用someObj.GetMyStrings() 吗?改为执行以下操作会更好:

List<string> myStrings = someObj.GetMyStrings();
foreach(string str in myStrings)
{
    // do some stuff
}

?

【问题讨论】:

  • 试试看 - 在GetMyStrings() 中放一个断点,看看调试器停在那里多少次!

标签: c# .net foreach


【解决方案1】:

该函数只被调用一次,返回一个IEnumerator&lt;T&gt;;之后,使用MoveNext() 方法和Current 属性对结果进行迭代:

foreach (Foo f in GetFoos())
{
    // Do stuff
}

有点等价于:

using (IEnumerator<Foo> iterator = GetFoos().GetEnumerator())
{
    while (iterator.MoveNext())
    {
        Foo f = iterator.Current;
        // Do stuff
    }
}

请注意,迭代器在最后被释放 - 这对于从迭代器块释放资源尤其重要,例如:

public IEnumerable<string> GetLines(string file)
{
    using (TextReader reader = File.OpenText(file))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            yield return line;
        }
    }
}

在上面的代码中,您确实希望在完成迭代时关闭文件,编译器巧妙地实现了IDisposable 以使其工作。

【讨论】:

  • 如果我错了,请纠正我,但我认为 C# 编译器不允许您在 foreach 循环运行时编辑 IEnumerable。
  • @ShaswatRungta:我不知道您所说的“编辑 IEnumerable”是什么意思,也不知道这与问题有什么关系。
  • 如果您在 foreach 开始执行后尝试编辑 IEnumerable,应用程序会在运行时抛出异常尝试运行此代码 pastebin.com/MztPyiuA
  • @ShaswatRungta:编译器不能抛出异常——它们在执行时不参与。而且您还没有说出“编辑 IEnumerable”是什么意思。我怀疑您对某些集合类型(例如List&lt;T&gt;)但已经到位的保护措施感到困惑。如果您在迭代 List&lt;T&gt; 时修改它,是的,您会遇到异常。这是List&lt;T&gt; 实现做出的决定——我看不出它与这个问题有什么关系。
  • @JonSkeet 我认为这是因为 List 被处理为 foreach 循环的 IEnumerable 并且循环不允许在迭代它时对其进行编辑。 [错误地使用了编译器这个词。我的意思是在运行时]
【解决方案2】:

不..该函数将被调用一次以获取 IEnumerable.. 然后将重复调用 MoveNext 和 Current。

【讨论】:

    【解决方案3】:

    GetMyStrings() 返回一个 IEnumerable 类型的对象。运行时知道如何处理它。它调用 IEnumerable.GetEnumerator(),然后在该枚举器对象上调用 MoveNext() 和 Current。

    【讨论】:

      【解决方案4】:

      只是为了解决问题,以防你陷入“所有的都是一样的”;

      for(int x=0;x < ProvideCeiling(); x++)
      

      是否每次都调用该函数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-16
        • 1970-01-01
        • 2013-09-14
        • 2019-02-18
        • 1970-01-01
        相关资源
        最近更新 更多