I know what yield
does, and I've seen a few examples, but I can't think of real life applications, have you used it to solve some specific problem?
我知道收益率是多少,而且我已经看过几个例子,但我想不到现实生活中的应用,你用它来解决一些具体问题吗?
(Ideally some problem that cannot be solved some other way)
(理想情况下,某些其他问题无法解决的问题)
7 个解决方案
#1
9
I realise this is an old question (pre Jon Skeet?) but I have been considering this question myself just lately. Unfortunately the current answers here (in my opinion) don't mention the most obvious advantage of the yield statement.
我意识到这是一个老问题(前Jon Skeet?)但我最近一直在考虑这个问题。不幸的是,目前的答案(在我看来)没有提到yield语句最明显的优势。
The biggest benefit of the yield statement is that it allows you to iterate over very large lists with much more efficient memory usage then using say a standard list.
yield语句的最大好处是它允许您使用更高效的内存使用来迭代非常大的列表,然后使用标准列表。
For example, let's say you have a database query that returns 1 million rows. You could retrieve all rows using a DataReader and store them in a List, therefore requiring list_size * row_size bytes of memory.
例如,假设您有一个返回100万行的数据库查询。您可以使用DataReader检索所有行并将它们存储在List中,因此需要list_size * row_size字节的内存。
Or you could use the yield statement to create an Iterator and only ever store one row in memory at a time. In effect this gives you the ability to provide a "streaming" capability over large sets of data.
或者您可以使用yield语句创建Iterator,并且一次只能在内存中存储一行。实际上,这使您能够在大型数据集上提供“流式”功能。
Moreover, in the code that uses the Iterator, you use a simple foreach loop and can decide to break out from the loop as required. If you do break early, you have not forced the retrieval of the entire set of data when you only needed the first 5 rows (for example).
此外,在使用Iterator的代码中,您使用一个简单的foreach循环,并可以根据需要决定从循环中断开。如果你提前中断,当你只需要前5行(例如)时,你并没有强制检索整个数据集。
Regarding:
Ideally some problem that cannot be solved some other way
The yield statement does not give you anything you could not do using your own custom iterator implementation, but it saves you needing to write the often complex code needed. There are very few problems (if any) that can't solved more than one way.
yield语句不会为您提供使用自己的自定义迭代器实现无法完成的任何操作,但它可以节省您需要编写所需的复杂代码。很少有问题(如果有的话)无法解决多种问题。
Here are a couple of more recent questions and answers that provide more detail:
以下是一些最近的问题和答案,提供了更多细节:
收益率关键字增值?
Is yield useful outside of LINQ?
LINQ之外的产量是否有用?
#2
5
actually I use it in a non traditional way on my site IdeaPipe
实际上我在我的网站IdeaPipe上以非传统的方式使用它
public override IEnumerator<T> GetEnumerator()
{
// goes through the collection and only returns the ones that are visible for the current user
// this is done at this level instead of the display level so that ideas do not bleed through
// on services
foreach (T idea in InternalCollection)
if (idea.IsViewingAuthorized)
yield return idea;
}
so basically it checks if viewing the idea is currently authorized and if it is it returns the idea. If it isn't, it is just skipped. This allows me to cache the Ideas but still display the ideas to the users that are authorized. Else I would have to re pull them each time based on permissions, when they are only re-ranked every 1 hour.
所以基本上它会检查当前是否已经授权查看该想法,如果是,则返回该想法。如果不是,则跳过它。这允许我缓存Ideas,但仍然向已授权的用户显示想法。否则,我每次必须根据权限重新拉取它们,而它们每1小时只重新排序一次。
#3
2
One interesting use is as a mechanism for asynchronous programming esp for tasks that take multiple steps and require the same set of data in each step. Two examples of this would be Jeffery Richters AysncEnumerator Part 1 and Part 2. The Concurrency and Coordination Runtime (CCR) also makes use of this technique CCR Iterators.
一个有趣的用途是作为异步编程esp的机制,用于执行多个步骤并在每个步骤中需要相同数据集的任务。两个例子是Jeffery Richters AysncEnumerator第1部分和第2部分。并发和协调运行时(CCR)也使用了这种技术CCR迭代器。
#4
1
LINQ's operators on the Enumerable class are implemented as iterators that are created with the yield statement. It allows you to chain operations like Select() and Where() without actually enumerating anything until you actually use the enumerator in a loop, typically by using the foreach statement. Also, since only one value is computed when you call IEnumerator.MoveNext() if you decide to stop mid-collection, you'll save the performance hit of calculating all of the results.
Enumerable类上的LINQ运算符实现为使用yield语句创建的迭代器。它允许您链接诸如Select()和Where()之类的操作,而不实际枚举任何内容,直到您在循环中实际使用枚举数,通常使用foreach语句。此外,因为如果您决定停止中间收集,则在调用IEnumerator.MoveNext()时只计算一个值,您将节省计算所有结果的性能损失。
Iterators can also be used to implement other kinds of lazy evaluation where expressions are evaluated only when you need it. You can also use yield for more fancy stuff like coroutines.
迭代器也可用于实现其他类型的延迟求值,其中表达式仅在您需要时进行求值。你也可以使用yield来获得更多花哨的东西,例如coroutines。
#5
1
Another good use for yield is to perform a function on the elements of an IEnumerable and to return a result of a different type, for example:
yield的另一个好用途是对IEnumerable的元素执行函数并返回不同类型的结果,例如:
public delegate T SomeDelegate(K obj);
public IEnumerable<T> DoActionOnList(IEnumerable<K> list, SomeDelegate action)
{
foreach (var i in list)
yield return action(i);
}
#6
1
Using yield can prevent downcasting to a concrete type. This is handy to ensure that the consumer of the collection doesn't manipulate it.
使用yield可以防止向下转换为具体类型。这样可以确保集合的使用者不会操纵它。
#7
0
You can also use yield return
to treat a series of function results as a list. For instance, consider a company that pays its employees every two weeks. One could retrieve a subset of payroll dates as a list using this code:
您还可以使用yield return将一系列函数结果视为列表。例如,考虑一家每两周向员工付款的公司。可以使用以下代码将工资核算日期的子集检索为列表:
void Main()
{
var StartDate = DateTime.Parse("01/01/2013");
var EndDate = DateTime.Parse("06/30/2013");
foreach (var d in GetPayrollDates(StartDate, EndDate)) {
Console.WriteLine(d);
}
}
// Calculate payroll dates in the given range.
// Assumes the first date given is a payroll date.
IEnumerable<DateTime> GetPayrollDates(DateTime startDate, DateTime endDate, int daysInPeriod = 14) {
var thisDate = startDate;
while (thisDate < endDate) {
yield return thisDate;
thisDate = thisDate.AddDays(daysInPeriod);
}
}
#1
9
I realise this is an old question (pre Jon Skeet?) but I have been considering this question myself just lately. Unfortunately the current answers here (in my opinion) don't mention the most obvious advantage of the yield statement.
我意识到这是一个老问题(前Jon Skeet?)但我最近一直在考虑这个问题。不幸的是,目前的答案(在我看来)没有提到yield语句最明显的优势。
The biggest benefit of the yield statement is that it allows you to iterate over very large lists with much more efficient memory usage then using say a standard list.
yield语句的最大好处是它允许您使用更高效的内存使用来迭代非常大的列表,然后使用标准列表。
For example, let's say you have a database query that returns 1 million rows. You could retrieve all rows using a DataReader and store them in a List, therefore requiring list_size * row_size bytes of memory.
例如,假设您有一个返回100万行的数据库查询。您可以使用DataReader检索所有行并将它们存储在List中,因此需要list_size * row_size字节的内存。
Or you could use the yield statement to create an Iterator and only ever store one row in memory at a time. In effect this gives you the ability to provide a "streaming" capability over large sets of data.
或者您可以使用yield语句创建Iterator,并且一次只能在内存中存储一行。实际上,这使您能够在大型数据集上提供“流式”功能。
Moreover, in the code that uses the Iterator, you use a simple foreach loop and can decide to break out from the loop as required. If you do break early, you have not forced the retrieval of the entire set of data when you only needed the first 5 rows (for example).
此外,在使用Iterator的代码中,您使用一个简单的foreach循环,并可以根据需要决定从循环中断开。如果你提前中断,当你只需要前5行(例如)时,你并没有强制检索整个数据集。
Regarding:
Ideally some problem that cannot be solved some other way
The yield statement does not give you anything you could not do using your own custom iterator implementation, but it saves you needing to write the often complex code needed. There are very few problems (if any) that can't solved more than one way.
yield语句不会为您提供使用自己的自定义迭代器实现无法完成的任何操作,但它可以节省您需要编写所需的复杂代码。很少有问题(如果有的话)无法解决多种问题。
Here are a couple of more recent questions and answers that provide more detail:
以下是一些最近的问题和答案,提供了更多细节:
收益率关键字增值?
Is yield useful outside of LINQ?
LINQ之外的产量是否有用?
#2
5
actually I use it in a non traditional way on my site IdeaPipe
实际上我在我的网站IdeaPipe上以非传统的方式使用它
public override IEnumerator<T> GetEnumerator()
{
// goes through the collection and only returns the ones that are visible for the current user
// this is done at this level instead of the display level so that ideas do not bleed through
// on services
foreach (T idea in InternalCollection)
if (idea.IsViewingAuthorized)
yield return idea;
}
so basically it checks if viewing the idea is currently authorized and if it is it returns the idea. If it isn't, it is just skipped. This allows me to cache the Ideas but still display the ideas to the users that are authorized. Else I would have to re pull them each time based on permissions, when they are only re-ranked every 1 hour.
所以基本上它会检查当前是否已经授权查看该想法,如果是,则返回该想法。如果不是,则跳过它。这允许我缓存Ideas,但仍然向已授权的用户显示想法。否则,我每次必须根据权限重新拉取它们,而它们每1小时只重新排序一次。
#3
2
One interesting use is as a mechanism for asynchronous programming esp for tasks that take multiple steps and require the same set of data in each step. Two examples of this would be Jeffery Richters AysncEnumerator Part 1 and Part 2. The Concurrency and Coordination Runtime (CCR) also makes use of this technique CCR Iterators.
一个有趣的用途是作为异步编程esp的机制,用于执行多个步骤并在每个步骤中需要相同数据集的任务。两个例子是Jeffery Richters AysncEnumerator第1部分和第2部分。并发和协调运行时(CCR)也使用了这种技术CCR迭代器。
#4
1
LINQ's operators on the Enumerable class are implemented as iterators that are created with the yield statement. It allows you to chain operations like Select() and Where() without actually enumerating anything until you actually use the enumerator in a loop, typically by using the foreach statement. Also, since only one value is computed when you call IEnumerator.MoveNext() if you decide to stop mid-collection, you'll save the performance hit of calculating all of the results.
Enumerable类上的LINQ运算符实现为使用yield语句创建的迭代器。它允许您链接诸如Select()和Where()之类的操作,而不实际枚举任何内容,直到您在循环中实际使用枚举数,通常使用foreach语句。此外,因为如果您决定停止中间收集,则在调用IEnumerator.MoveNext()时只计算一个值,您将节省计算所有结果的性能损失。
Iterators can also be used to implement other kinds of lazy evaluation where expressions are evaluated only when you need it. You can also use yield for more fancy stuff like coroutines.
迭代器也可用于实现其他类型的延迟求值,其中表达式仅在您需要时进行求值。你也可以使用yield来获得更多花哨的东西,例如coroutines。
#5
1
Another good use for yield is to perform a function on the elements of an IEnumerable and to return a result of a different type, for example:
yield的另一个好用途是对IEnumerable的元素执行函数并返回不同类型的结果,例如:
public delegate T SomeDelegate(K obj);
public IEnumerable<T> DoActionOnList(IEnumerable<K> list, SomeDelegate action)
{
foreach (var i in list)
yield return action(i);
}
#6
1
Using yield can prevent downcasting to a concrete type. This is handy to ensure that the consumer of the collection doesn't manipulate it.
使用yield可以防止向下转换为具体类型。这样可以确保集合的使用者不会操纵它。
#7
0
You can also use yield return
to treat a series of function results as a list. For instance, consider a company that pays its employees every two weeks. One could retrieve a subset of payroll dates as a list using this code:
您还可以使用yield return将一系列函数结果视为列表。例如,考虑一家每两周向员工付款的公司。可以使用以下代码将工资核算日期的子集检索为列表:
void Main()
{
var StartDate = DateTime.Parse("01/01/2013");
var EndDate = DateTime.Parse("06/30/2013");
foreach (var d in GetPayrollDates(StartDate, EndDate)) {
Console.WriteLine(d);
}
}
// Calculate payroll dates in the given range.
// Assumes the first date given is a payroll date.
IEnumerable<DateTime> GetPayrollDates(DateTime startDate, DateTime endDate, int daysInPeriod = 14) {
var thisDate = startDate;
while (thisDate < endDate) {
yield return thisDate;
thisDate = thisDate.AddDays(daysInPeriod);
}
}