“屈服”打破了什么?用c#做什么?

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

186190 次浏览

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

告诉迭代器它已经到达终点。

举个例子:

public interface INode
{
IEnumerable<Node> GetChildren();
}


public class NodeWithTenChildren : INode
{
private Node[] m_children = new Node[10];


public IEnumerable<Node> GetChildren()
{
for( int n = 0; n < 10; ++n )
{
yield return m_children[ n ];
}
}
}


public class NodeWithNoChildren : INode
{
public IEnumerable<Node> GetChildren()
{
yield break;
}
}

它指定迭代器已经结束。您可以将yield break看作不返回值的return语句。

例如,如果你将一个函数定义为迭代器,函数体可能是这样的:

for (int i = 0; i < 5; i++)
{
yield return i;
}


Console.Out.WriteLine("You will see me");

注意,在循环完成所有循环后,最后一行执行,您将在控制台应用程序中看到消息。

或者像这样使用yield break:

int i = 0;
while (true)
{
if (i < 5)
{
yield return i;
}
else
{
// note that i++ will not be executed after this
yield break;
}
i++;
}


Console.Out.WriteLine("Won't see me");

在这种情况下,最后一条语句永远不会执行,因为我们提前离开了函数。

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

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

yield break就像一个线程到达其函数的末尾并终止。

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

http://www.alteridem.net/2007/08/22/the-yield-statement-in-c/是一个很好的例子:

public static IEnumerable<int> Range( int min, int max )
{
while ( true )
{
if ( min >= max )
{
yield break;
}
yield return min++;
}
}

和解释,如果在一个方法中命中了yield break语句,该方法的执行将停止而不返回。在某些情况下,当你不想给出任何结果时,你可以使用yield break。

yield关键字与return关键字一起使用,为枚举器对象提供一个值。收益回报指定返回的值。当到达yield return语句时,存储当前位置。下次调用迭代器时,从这个位置重新开始执行。

用一个例子来解释它的意思:

    public IEnumerable<int> SampleNumbers()
{
int counter = 0;
yield return counter;


counter = counter + 2;


yield return counter;


counter = counter + 3;


yield return counter ;
}

迭代时返回的值为:0,2,5。

在第二次迭代返回值2之后,第三次迭代从之前的位置开始,同时保留名为计数器的局部变量之前的值2。

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(..)

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

// 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;
}