什么时候是“产量”?真的需要吗?

发布于 2024-09-04 18:24:46 字数 204 浏览 6 评论 0原文

可能的重复:
C# - 正确使用收益回报

C# 的真实用例是什么屈服?

谢谢。

Possible Duplicate:
C# - Proper Use of yield return

What can be a real use case for C# yield?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

吝吻 2024-09-11 18:24:46

当您想要延迟执行时。

这在大多数情况下是有意义的,替代方案是构造临时集合。

考虑这种情况:我有一个整数列表,我想列出它们的平方。

我可以这样做:

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

然后我可以对平方求和,取平均值,找到最大的,等等。

但我真的不需要为此目的填充一个全新的 List 。我可以使用 yield 枚举初始列表并一一返回平方:

public static IEnumerable<int> Squares(this IEnumerable<int> numbers) {
    foreach (int number in numbers)
        yield return number * number;
}

直到您开始处理非常大的集合之前,这实际上会产生差异的事实可能并不明显,事实证明,填充临时集合是相当浪费的。

例如,假设我想找到高于某个阈值的第一个方块。我可以这样做:

IEnumerable<int> numbers = GetLotsOfNumbers();
var squares = numbers.Squares();
int firstBigSquare = squares
    .Where(x => x >= 1000)
    .FirstOrDefault();

但是,如果我的 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:

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.

稍尽春風 2024-09-11 18:24:46

来自 MSDN 页面 yield< /a>:

在迭代器块中使用,为枚举器对象提供值或表示迭代结束。

您在创建自定义迭代器时使用它。使用页面中的示例:

// 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 循环在每次迭代后有效地“暂停”,以允许调用例程执行一些操作。在本例中打印结果。

From the MSDN page on yield:

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.

寂寞陪衬 2024-09-11 18:24:46

当您懒得编写自己的 IEnumerator ;)

When you're too lazy to write your own IEnumerator ;)

自找没趣 2024-09-11 18:24:46

请参阅本文

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文