.net 什么是“收益率打破;“用C#做什么?

uqzxnwby  于 2023-01-31  发布在  .NET
关注(0)|答案(9)|浏览(163)

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

dsekswqp

dsekswqp1#

它表示迭代器已经结束,你可以把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");

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

2fjabf4q

2fjabf4q2#

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

8gsdolmq

8gsdolmq3#

告诉迭代器它已经到达末尾。
例如:

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

a2mppw5e4#

yield基本上使IEnumerable<T>方法的行为类似于协作地(与抢先地相反)调度的线程。
yield return就像一个线程调用“schedule”或“sleep”函数来给予对CPU的控制。就像一个线程一样,IEnumerable<T>方法在紧接着的时间点重新获得控制,所有局部变量的值都与放弃控制之前的值相同。
yield break就像一个线程到达其函数的末尾并终止。
人们谈论“状态机”,但状态机实际上就是“线程”的全部。线程有一些状态(即局部变量的值),并且每次调度它时,它都会执行一些操作(s)才能到达一个新的状态。关于yield的关键点是,与我们习惯的操作系统线程不同,使用它的代码被及时冻结,直到迭代被手动推进或终止。

mgdq6dx1

mgdq6dx15#

yield break只是最后一次返回的一种方式,不返回任何值
例如

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

eblbsuwk6#

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

ffx8fchx

ffx8fchx7#

这里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。

kqhtkvqz

kqhtkvqz8#

除了其他好的答案之外,注意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
tyg4sfes

tyg4sfes9#

yield关键字与return关键字一起使用,为枚举器对象提供值。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.

**需要注意的是,本例中的 counter 变量是一个局部变量。**在返回值2的第二次迭代之后,第三次迭代从它之前离开的地方开始,同时保留名为 counter 的局部变量的先前值2。

相关问题