This makes sense in most cases where the alternative is to construct a temporary collection.
Consider this scenario: I have a list of integers and I want to list their squares.
I could do this:
public static IEnumerable<int> Squares(this IEnumerable<int> numbers) {
List<int> squares = new List<int>();
foreach (int number in numbers)
squares.Add(number * number);
return squares;
}
Then I could sum the squares, take their average, find the greatest, etc.
But I really didn't need to populate a whole new List<int> for that purpose. I could've used yield to enumerate over the initial list and return the squares one-by-one:
public static IEnumerable<int> Squares(this IEnumerable<int> numbers) {
foreach (int number in numbers)
yield return number * number;
}
The fact that this actually makes a difference might not be apparent until you start dealing with very large collections, where populating temporary collections proves to be quite wasteful.
For example suppose I wanted to find the first square above a certain threshold. I could do this:
IEnumerable<int> numbers = GetLotsOfNumbers();
var squares = numbers.Squares();
int firstBigSquare = squares
.Where(x => x >= 1000)
.FirstOrDefault();
But if my Squares method populated an entire List<int> before returning, the above code would be doing potentially far more work than necessary.
// yield-example.cs
using System;
using System.Collections;
public class List
{
public static IEnumerable Power(int number, int exponent)
{
int counter = 0;
int result = 1;
while (counter++ < exponent)
{
result = result * number;
yield return result;
}
}
static void Main()
{
// Display powers of 2 up to the exponent 8:
foreach (int i in Power(2, 8))
{
Console.Write("{0} ", i);
}
}
}
yield 意味着 Power 内的 while 循环在每次迭代后有效地“暂停”,以允许调用例程执行一些操作。在本例中打印结果。
Used in an iterator block to provide a value to the enumerator object or to signal the end of iteration.
You use it when creating a custom iterator. Using the example from the page:
// yield-example.cs
using System;
using System.Collections;
public class List
{
public static IEnumerable Power(int number, int exponent)
{
int counter = 0;
int result = 1;
while (counter++ < exponent)
{
result = result * number;
yield return result;
}
}
static void Main()
{
// Display powers of 2 up to the exponent 8:
foreach (int i in Power(2, 8))
{
Console.Write("{0} ", i);
}
}
}
The yield means that the while loop inside Power effectively "pauses" after each iteration to allow the calling routine to perform some action. In this case printing out the result.
Yield acts as a return-placeholder - it's a non-local goto return point which preserves the method's environment and allows the code to "jump" back in. In a way similar (kind of inverted) to passing a delegate into a method which allows you to inject specific logic within another method, closures allow you to do different types of work "around" a more general method, allowing you to keep code small and modular and re-usable.
This could make for much more efficient code. Instead of instantiating a very large collection, it might be possible to allow individual objects to be acted upon in sequence(and they are discarded after each operation). I imagine you could construct cases where a straightforward iterator would be extremely difficult to build.
发布评论
评论(4)
当您想要延迟执行时。
这在大多数情况下是有意义的,替代方案是构造临时集合。
考虑这种情况:我有一个整数列表,我想列出它们的平方。
我可以这样做:
然后我可以对平方求和,取平均值,找到最大的,等等。
但我真的不需要为此目的填充一个全新的
List
。我可以使用yield
枚举初始列表并一一返回平方:直到您开始处理非常大的集合之前,这实际上会产生差异的事实可能并不明显,事实证明,填充临时集合是相当浪费的。
例如,假设我想找到高于某个阈值的第一个方块。我可以这样做:
但是,如果我的
Squares
方法在返回之前填充了整个List
,则上面的代码可能会做更多的事情。比必要的工作。When you want deferred execution.
This makes sense in most cases where the alternative is to construct a temporary collection.
Consider this scenario: I have a list of integers and I want to list their squares.
I could do this:
Then I could sum the squares, take their average, find the greatest, etc.
But I really didn't need to populate a whole new
List<int>
for that purpose. I could've usedyield
to enumerate over the initial list and return the squares one-by-one:The fact that this actually makes a difference might not be apparent until you start dealing with very large collections, where populating temporary collections proves to be quite wasteful.
For example suppose I wanted to find the first square above a certain threshold. I could do this:
But if my
Squares
method populated an entireList<int>
before returning, the above code would be doing potentially far more work than necessary.来自 MSDN 页面
yield
< /a>:您在创建自定义迭代器时使用它。使用页面中的示例:
yield
意味着Power
内的while
循环在每次迭代后有效地“暂停”,以允许调用例程执行一些操作。在本例中打印结果。From the MSDN page on
yield
:You use it when creating a custom iterator. Using the example from the page:
The
yield
means that thewhile
loop insidePower
effectively "pauses" after each iteration to allow the calling routine to perform some action. In this case printing out the result.当您懒得编写自己的 IEnumerator ;)
When you're too lazy to write your own IEnumerator ;)
请参阅本文。
Yield 充当返回占位符 - 它是一个非本地 goto 返回点,它保留方法的环境并允许代码“跳”回来。以类似于(有点相反)将委托传递到方法的方式,该方法允许当您在另一个方法中注入特定逻辑时,闭包允许您“围绕”更通用的方法执行不同类型的工作,从而使代码保持小型、模块化和可重用。
这可以使代码更加高效。可以允许按顺序对单个对象进行操作(并且在每次操作后将其丢弃),而不是实例化一个非常大的集合。我想您可能会构建一个非常难以构建简单迭代器的情况。
See this article.
Yield acts as a return-placeholder - it's a non-local goto return point which preserves the method's environment and allows the code to "jump" back in. In a way similar (kind of inverted) to passing a delegate into a method which allows you to inject specific logic within another method, closures allow you to do different types of work "around" a more general method, allowing you to keep code small and modular and re-usable.
This could make for much more efficient code. Instead of instantiating a very large collection, it might be possible to allow individual objects to be acted upon in sequence(and they are discarded after each operation). I imagine you could construct cases where a straightforward iterator would be extremely difficult to build.