【问题标题】:How to avoid Iterator method being restarted?如何避免重新启动迭代器方法?
【发布时间】:2013-02-19 22:03:51
【问题描述】:

请考虑以下 C# 块:

int resultIndex = 0;

Result firstResult = results.First();
DoAVeryImportOperationWithFirstResult(firstResult);

Console.WriteLine(String.Format("This is the {0} result.", resultIndex++));
yield return firstResult;

foreach(Result result in results)
{
   Console.WriteLine(String.Format("This is the {0} result.", resultIndex++));
   yield return result;
}

如果您熟悉 Linq 和迭代器,您会注意到在 foreach 块的第一次迭代中,将返回 results 的第一个结果,而不是第二个。

所以,基本上这是我的问题:我无法从迭代器方法中获取第一个值,然后在不重新启动此方法的情况下在其他地方使用它。

有人知道一些解决方法吗?

【问题讨论】:

    标签: c# linq iterator yield-return


    【解决方案1】:

    其他人已经展示了使用foreach 循环和条件执行的方法。这实际上是一种巧妙的方法 - 但这是另一种选择,以防 foreach 循环因任何原因不合适。

    using (var iterator = results.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            // Throw some appropriate exception here.
        }
    
        Result firstResult = iterator.Current;
        DoAVeryImportOperationWithFirstResult(firstResult);
    
        Console.WriteLine(String.Format("This is the {0} result.", resultIndex++));
        yield return firstResult;
    
        while (iterator.MoveNext())
        {
            Result result = iterator.Current;
            Console.WriteLine(String.Format("This is the {0} result.", resultIndex++));
            yield return result;
        }
    }
    

    【讨论】:

    • 该死!再次击败它。
    【解决方案2】:

    只要明确地去做:

    bool first = true;
    foreach(var item in results) {
        if(first) {
            first = false;
            // whatever
        } else {
            // whatever else
        }
    }
    

    或更复杂的:

    using(var iter = results.GetEnumerator()) {
        if(iter.MoveNext()) {
            // do first things with iter.Current
    
            while(iter.MoveNext()) {
                // do non-first things with iter.Current
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      你需要手动迭代:

      var enumerator = results.GetEnumerator();
      enumerator.MoveNext();
      yield return enumerator.Current; //first
      while(enumerator.MoveNext())
       yield return enumerator.Current; //2nd, ...
      

      省略所有错误检查...也不要忘记处理。

      【讨论】:

        【解决方案4】:
        bool isFirst = true;
        foreach(Result result in results)
        {
           if(isFirst)
           {
              DoAVeryImportOperationWithFirstResult(firstResult);
              isFirst = false;
           }
        
           Console.WriteLine(String.Format("This is the {0} result.", resultIndex++));
           yield return result;
        }
        

        【讨论】:

          【解决方案5】:

          你需要使用Skip

          foreach(Result result in results.Skip(1))
          {
             Console.WriteLine(String.Format("This is the {0} result.", resultIndex++));
             yield return result;
          }
          

          或手动迭代结果。

          如果您考虑一下迭代器是如何实现的,那么您所看到的确实是预期的行为!

          【讨论】:

          • 请注意,这样做涉及对源序列进行两次迭代。在许多实际情况下这很好,但在一般情况下则不然。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-18
          • 2011-11-18
          • 2020-03-02
          • 1970-01-01
          • 2014-07-03
          • 1970-01-01
          相关资源
          最近更新 更多