我在MSDN中见过这种语法:yield break,但我不知道它是做什么的。有人知道吗?


当前回答

除了其他好的答案外,请注意yield break在涉及嵌套循环时不像普通的break那样工作。break只会停止当前循环,而不会停止任何外部循环,yield break将停止整个枚举:

IEnumerable<int> Iterate() {
  for(int i=0; i<5; i++) {
    yield return i;

    for(int j=0; j<5; j++) {
      if ((i*10 + j) > 30)
        // This will stop the whole enumeration, even if there's
        // an outer "for" loop
        yield break;

      yield return (i*10 + j);
    }
  }
}

Console.WriteLine(string.Join(", ", Iterate().Select(i => i.ToString())));
// 0, 0, 1, 2, 3, 4, 1, 10, 11, 12, 13, 14, 2, 20, 21, 22, 23, 24, 3, 30

其他回答

yield基本上使IEnumerable<T>方法的行为类似于协作(而不是抢先)调度线程。

yield return就像一个线程调用“schedule”或“sleep”函数来放弃对CPU的控制。就像线程一样,IEnumerable<T>方法在结束后立即恢复控制,所有局部变量的值与放弃控制之前的值相同。

屈服断裂就像一个线程到达其功能的末端并终止。

人们谈论“状态机”,但状态机其实就是“线程”。一个线程有一些状态(即局部变量的值),每次调度它都会采取一些操作来达到一个新的状态。yield的关键在于,与我们所习惯的操作系统线程不同,使用它的代码在迭代被手动推进或终止之前是固定的。

结束迭代器块(例如,表示IEnumerable中没有更多的元素)。

yield break语句导致枚举停止。实际上,yield break完成了枚举,而不返回任何附加项。

考虑到迭代器方法实际上有两种停止迭代的方式。在一种情况下,方法的逻辑可以在返回所有项后自然退出方法。这里有一个例子:

IEnumerable<uint> FindPrimes(uint startAt, uint maxCount)
{
    for (var i = 0UL; i < maxCount; i++)
    {
        startAt = NextPrime(startAt);
        yield return startAt;
    }

    Debug.WriteLine("All the primes were found.");
}

在上面的例子中,一旦找到maxCount质数,迭代器方法自然会停止执行。

yield break语句是迭代器停止枚举的另一种方式。这是一种提前跳出枚举的方法。这里是与上面相同的方法。这一次,该方法对该方法可以执行的时间有一个限制。

IEnumerable<uint> FindPrimes(uint startAt, uint maxCount, int maxMinutes)
{
    var sw = System.Diagnostics.Stopwatch.StartNew();
    for (var i = 0UL; i < maxCount; i++)
    {
        startAt = NextPrime(startAt);
        yield return startAt;

        if (sw.Elapsed.TotalMinutes > maxMinutes)
            yield break;
    }

    Debug.WriteLine("All the primes were found.");
}

注意yield break的调用。实际上,它提早退出枚举。

还要注意,yield break与普通break的工作方式不同。在上面的例子中,yield break退出方法而不调用Debug.WriteLine(..)。

收益率突破只是一种表示最后一次返回并且不返回任何值的方式

e.g

// returns 1,2,3,4,5
IEnumerable<int> CountToFive()
{
    yield return 1;
    yield return 2;
    yield return 3;
    yield return 4;
    yield return 5;
    yield break;
    yield return 6;
    yield return 7;
    yield return 8;
    yield return 9;
 }

除了其他好的答案外,请注意yield break在涉及嵌套循环时不像普通的break那样工作。break只会停止当前循环,而不会停止任何外部循环,yield break将停止整个枚举:

IEnumerable<int> Iterate() {
  for(int i=0; i<5; i++) {
    yield return i;

    for(int j=0; j<5; j++) {
      if ((i*10 + j) > 30)
        // This will stop the whole enumeration, even if there's
        // an outer "for" loop
        yield break;

      yield return (i*10 + j);
    }
  }
}

Console.WriteLine(string.Join(", ", Iterate().Select(i => i.ToString())));
// 0, 0, 1, 2, 3, 4, 1, 10, 11, 12, 13, 14, 2, 20, 21, 22, 23, 24, 3, 30