C# 收益率在现实生活中的应用是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17125/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What are real life applications of yield?
提问by juan
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?
我知道是什么yield
,也看过几个例子,但是想不到现实生活中的应用,你有没有用它来解决一些具体的问题?
(Ideally some problem that cannot be solved some other way)
(理想情况下,一些无法通过其他方式解决的问题)
采纳答案by Ash
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_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 语句创建一个迭代器,并且一次只在内存中存储一行。实际上,这使您能够为大型数据集提供“流”功能。
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).
此外,在使用迭代器的代码中,您使用了一个简单的 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:
以下是提供更多详细信息的几个最近的问题和答案:
回答by Nick Berardi
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.
所以基本上它会检查当前是否已授权查看该想法,如果是,则返回该想法。如果不是,它只是被跳过。这允许我缓存创意,但仍向授权用户显示创意。否则,当它们每 1 小时重新排名时,我每次都必须根据权限重新拉动它们。
回答by Mark Cidade
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 foreachstatement. 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 yieldfor more fancy stuff like coroutines.
迭代器还可用于实现其他类型的惰性求值,其中仅在需要时才对表达式求值。您还可以将yield用于更花哨的东西,例如协程。
回答by Jon Limjap
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);
}
回答by denis phillips
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 1and Part 2. The Concurrency and Coordination Runtime (CCR) also makes use of this technique CCR Iterators.
一个有趣的用途是作为异步编程的机制,特别是用于执行多个步骤并在每个步骤中需要相同数据集的任务。这方面的两个示例是 Jeffery Richters AysncEnumerator Part 1和Part 2。并发和协调运行时 (CCR) 也使用了这种技术CCR Iterators。
回答by Scott Muc
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 可以防止向下转换为具体类型。这有助于确保集合的使用者不会操作它。
回答by Terry Lewis
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);
}
}