什么是;屈服断裂&引用;你用C#做什么?
我在MSDN:中见过这种语法,但我不知道它的作用。有人知道吗?结束迭代器块(例如,表示IEnumerable中没有更多元素)。告诉迭代器它已到达末尾 例如:什么是;屈服断裂&引用;你用C#做什么?,c#,.net,yield,C#,.net,Yield,我在MSDN:中见过这种语法,但我不知道它的作用。有人知道吗?结束迭代器块(例如,表示IEnumerable中没有更多元素)。告诉迭代器它已到达末尾 例如: public interface INode { IEnumerable<Node> GetChildren(); } public class NodeWithTenChildren : INode { private Node[] m_children = new Node[10]; public
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;
}
}
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.");
}
公共接口INode
{
IEnumerable GetChildren();
}
公共类NodeWithTenChildren:INode
{
私有节点[]m_children=新节点[10];
公共IEnumerable GetChildren()
{
对于(int n=0;n<10;++n)
{
收益率m_子项[n];
}
}
}
公共类NodeWithNoChildren:INode
{
公共IEnumerable GetChildren()
{
屈服断裂;
}
}
它指定迭代器已结束。您可以将yieldbreak
视为不返回值的return
语句
例如,如果将函数定义为迭代器,则函数体可能如下所示:
for (int i = 0; i < 5; i++)
{
yield return i;
}
Console.Out.WriteLine("You will see me");
在这种情况下,最后一条语句永远不会执行,因为我们提前离开了函数。
yield
基本上使IEnumerable
方法的行为类似于协作(而不是抢占)调度线程
yield return
就像一个线程调用“schedule”或“sleep”函数来放弃对CPU的控制。就像一个线程一样,IEnumerable
方法在随后立即恢复控件,所有局部变量的值与放弃控件之前的值相同
yield break
就像一个线程到达其功能的末尾并终止
人们谈论“状态机”,但状态机实际上是一条“线”。线程具有某些状态(即局部变量的值),每次调度线程时,它都会采取一些操作以达到新状态。关于yield
的关键点是,与我们习惯的操作系统线程不同,使用它的代码会在时间上冻结,直到手动推进或终止迭代。下面是一个很好的例子:
public static IEnumerable<int> Range( int min, int max )
{
while ( true )
{
if ( min >= max )
{
yield break;
}
yield return min++;
}
}
公共静态IEnumerable范围(最小整数、最大整数)
{
while(true)
{
如果(最小值>=最大值)
{
屈服断裂;
}
收益率min++;
}
}
还有一个解释,如果在一个方法中命中了
yieldbreak
语句,则该方法的执行将停止而不返回。在某些情况下,当您不想给出任何结果时,可以使用yield break。yield关键字与return关键字一起使用,以向枚举器对象提供值收益率返回指定返回的一个或多个值。当到达yield return语句时,将存储当前位置。下次调用迭代器时,将从此位置重新启动执行
要使用示例来解释其含义,请执行以下操作:
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;
}
}
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.");
}
public IEnumerable SampleNumbers()
{
int计数器=0;
收益返回计数器;
计数器=计数器+2;
收益返回计数器;
计数器=计数器+3;
收益返回计数器;
}
迭代时返回的值为:0、2、5
需要注意的是,本例中的计数器变量是一个局部变量。在返回值2的第二次迭代后,第三次迭代从之前的位置开始,保留名为counter的局部变量先前的值2。语句导致枚举停止。实际上,
yield break
在不返回任何附加项的情况下完成枚举
假设迭代器方法实际上有两种停止迭代的方法。在一种情况下,该方法的逻辑可以在返回所有项后自然退出该方法。以下是一个例子:
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;
}
}
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.");
}
请注意对屈服中断的调用。实际上,它提前退出枚举
还要注意的是,yield break
的工作原理与普通的break
不同。在上面的示例中,yield break
退出该方法,而不调用Debug.WriteLine(..)yield break只是表示最后一次返回,不返回任何值
e、 g
//返回1,2,3,4,5
IEnumerable CountToFive()
{
收益率1;
收益率2;
收益率3;
收益率4;
收益率5;
屈服断裂;
收益率6;
收益率7;
收益率8;
收益率9;
}
您没有解释什么是收益率中断
我认为收益率返回
实际上不支持返回多个值。也许这不是你真正的意思,但我就是这么理解的。Sam——具有多个yield-return语句的SampleNumbers方法实际上是有效的,迭代器的值会立即返回,并且在请求下一个值时会继续执行。我见过有人用“产量突破”来结束这种方法,但这是不必要的。命中方法的结尾也会结束迭代器这是产量中断
的一个不好的例子,因为它不包含语言级枚举器,例如foreach
——当使用枚举器时,产量中断
提供实际值。这个例子看起来像一个展开的循环。在现实世界中,你几乎看不到这段代码(当然,我们都能想到一些边缘情况),而且,这里没有“迭代器”。作为语言规范,“迭代器块”不能扩展到方法之外。实际返回的是一个“可枚举的”,另请参见:Yield return不需要支持列表,也就是说,您不需要编写类似于MyList的代码。添加(…)
只需执行Yield return…
。如果您需要提前中断循环并返回虚拟支持列表,则使用屈服中断;