0

我经常发现我使用语句返回一个 IEnumerable 的场景yield return,然后有其他方法使用不同的参数调用这个函数并直接返回结果。

yield return与简单地返回集合相比,遍历结束这些结果的结果是否有任何性能优势?即,如果我return在生成的 IEnumberable 上使用而不是再次循环遍历这些结果并使用yield return编译器是否知道仅在需要时生成结果,还是在返回所有结果之前等待返回整个集合?

public class Demo
{
    private IEnumerable<int> GetNumbers(int x)
    {
        //imagine this operation were more expensive than this demo version
        //e.g. calling a web service on each iteration.
        for (int i = 0; i < x; i++)
        {
            yield return i;
        }
    }
    //does this wait for the full list before returning
    public IEnumerable<int> GetNumbersWrapped()
    {
        return GetNumbers(10);
    }
    //whilst this allows the benefits of Yield Return to persist?
    public IEnumerable<int> GetNumbersWrappedYield()
    {
        foreach (int i in GetNumbers(10))
            yield return i;
    }
}
4

4 回答 4

3

GetNumbersWrapped只是通过原始可枚举 - 它甚至还没有调用迭代器。最终结果仍然是完全延迟/懒惰/假脱机/其他。

GetNumbersWrappedYield添加了额外的抽象层 - 所以现在,每次调用MoveNext必须做更多的工作;不足以引起疼痛。它也将被完全延迟/懒惰/假脱机/其他任何东西 - 但会增加一些小开销。通常这些较小的开销是合理的,因为您正在添加一些价值,例如过滤或附加处理;但在此示例中并非如此。

注意:GetNumbersWrappedYield 确实要做的一件事是防止来电者滥用。例如,如果GetNumbers是:

private IEnumerable<int> GetNumbers(int x)
{
    return myPrivateSecretList;
}

然后调用者GetNumbersWrapped可以滥用这个:

IList list = (IList)GetNumbers(4);
list.Clear();
list.Add(123); // mwahahaahahahah

但是,调用者GetNumbersWrappedYield 不能这样做……至少,不那么容易。当然,他们仍然可以使用反射将迭代器分开,获取包装的内部引用,然后将其转换为.

然而,这通常不是真正的问题。

于 2013-08-28T11:03:38.790 回答
1

返回 an 的函数确实返回了一个对象,该对象不是完整列表,但知道在调用IEnumberable<T>其方法时如何迭代它。您上面的方法也是如此。它不会等待完整的集合。它返回一个有内部的对象。每当循环(或其他循环操作)调用此枚举器的方法时,它就会开始读取值。所以和是相同的,只是有一个冗余循环层。EnumeratorMoveNextGetNumbersWrappedEnumeratorforeachMoveNextGetNumbersWrappedGetNumbersWrappedYieldGetNumbersWrappedYield

于 2013-08-28T11:02:05.680 回答
1

如果我正确理解您的问题,该函数GetNumbersWrapped在返回之前不会等待完整列表,因为它的返回类型是 IEnumerable 并且内部循环的执行GetNumbers被延迟。

于 2013-08-28T11:03:11.293 回答
1

你可能知道,IEnumerable<T>是懒惰地评估。这意味着所有三种方法都将有效地做同样的事情,但GetNumbersWrappedYield只是被包装在一个冗余的枚举器中。这样做不会有任何性能优势,事实上,额外的枚举器会引入一点开销。我会坚持GetNumbers直接。

于 2013-08-28T11:03:45.917 回答