什么是收益的现实应用?

时间:2008-08-19 22:45:19

标签: c# .net yield

我知道yield做了什么,我看过几个例子,但我想不到现实生活中的应用,你用它来解决一些具体问题吗?

(理想情况下某些问题无法以其他方式解决)

7 个答案:

答案 0 :(得分:11)

我意识到这是一个老问题(前Jon Skeet?)但我最近一直在考虑这个问题。不幸的是,这里的答案(在我看来)并没有提到yield语句最明显的优势。

yield语句的最大好处是它允许您使用更高效的内存使用来迭代非常大的列表,然后使用标准列表。

例如,假设您有一个返回100万行的数据库查询。您可以使用DataReader检索所有行并将它们存储在List中,因此需要list_size * row_size字节的内存。

或者您可以使用yield语句创建Iterator,并且一次只能在内存中存储一​​行。实际上,这使您能够在大型数据集上提供“流式”功能。

此外,在使用Iterator的代码中,您使用一个简单的foreach循环,并可以根据需要决定从循环中分离出来。如果你提前中断,当你只需要前5行时(例如),你没有强制检索整个数据集。

关于:

Ideally some problem that cannot be solved some other way

yield语句不会为您提供使用自己的自定义迭代器实现无法完成的任何操作,但它可以节省您需要编写所需的常常复杂代码。很少有问题(如果有的话)无法解决多种问题。

以下是一些更新的问题和答案,提供了更多详细信息:

Yield keyword value added?

Is yield useful outside of LINQ?

答案 1 :(得分:5)

实际上我在网站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;
}

所以基本上它检查查看该想法目前是否已获得授权,如果是,则返回该想法。如果不是,则跳过它。这允许我缓存Ideas,但仍然将想法显示给授权的用户。否则,我每次都必须根据权限重新拉取它们,当它们每1小时重新排名时。

答案 2 :(得分:2)

一个有趣的用途是作为异步编程的机制esp,用于执行多个步骤并在每个步骤中需要相同数据集的任务。两个例子是Jeffery Richters AysncEnumerator Part 1Part 2。并发和协调运行时(CCR)也使用了这种技术CCR Iterators

答案 3 :(得分:1)

Enumerable类上的LINQ运算符是作为使用yield语句创建的迭代器实现的。它允许您链接诸如Select()和Where()之类的操作,而不实际枚举任何内容,直到您在循环中实际使用枚举器,通常使用 foreach 语句。此外,由于如果您决定停止中间收集,则在调用IEnumerator.MoveNext()时只计算一个值,您将保存计算所有结果的性能损失。

迭代器也可用于实现其他类型的延迟求值,其中表达式仅在您需要时进行求值。你也可以使用 yield 来获得更多像coroutines这样的花哨的东西。

答案 4 :(得分:1)

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

答案 5 :(得分:1)

使用yield可以防止向下转换为具体类型。这样可以确保集合的使用者不会操纵它。

答案 6 :(得分:0)

您还可以使用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);
    }
}