繁体   English   中英

在C#中返回IEnumerable实例和yield return语句之间的确切区别是什么?

[英]What is the exact difference between returning an IEnumerable instance and the yield return statement in C#

目前我正在使用一些通过迭代器应用延迟执行的库。 在某些情况下,我需要简单地“转发”收到的迭代器。 即我必须从被调用的方法获取IEnumerable<T>实例并立即返回它。

现在我的问题:简单地返回收到的IEnumerable<T>或通过循环重新产生它之间是否存在相关区别?

IEnumerable<int> GetByReturn()
{
    return GetIterator(); // GetIterator() returns IEnumerable<int>
}
// or:
IEnumerable<int> GetByReYielding()
{
    for(var item in GetIterator()) // GetIterator() returns IEnumerable<int>
    {
        yield return item;
    }
}

阅读Jon Skeet关于C#迭代器的文章可能值得你去参考。 这是非常有益的。

http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx

它们是不同的。 例如,如果GetIterator()声明为:

IEnumerable<int> GetIterator() {
    List<int> result = new List<int>();
    for(int i = 0; i < 1000; i++) {
        result.Add(i);
    }
    return result;
}

如果不进行重新生成, GetIterator()立即执行GetIterator()和循环。 因此,答案取决于您如何实现GetIterator() 如果确定GetIterator()将会屈服,那么重新产生它就没有意义了。

除了代码膨胀之外,我没有看到任何相关的区别。

两者之间没有任何相关的差异(除了可能的性能),因为你没有使用GetIterator()的枚举器做任何事情。 如果您要对枚举器执行某些操作(例如过滤器),那么重新收益才有意义。

有一个相关的区别。

GetByReYielding()的执行将以延迟方式执行(因为它是迭代器块)。 如果您在GetByReturn()或GetByReYielding()中使用了一个参数并在运行时检查该参数是否为null(或进行了任何其他验证),则在调用GetByReturn()时立即执行此检查,但在调用GetByReYielding()时不立即执行此检查! 当迭代结果时,GetByReYielding()中的验证将以延迟方式执行。 - 这通常是“太晚了”。 看这里:

// Checks parameters early. - Fine. The passed argument will be checked directly when
// GetByReturn() is called.
IEnumerable<int> GetByReturn(IEnumerable<int> sequence)
{
    if(null == sequence)
    {
        throw new ArgumentNullException("sequence");
    }

    return GetIterator();
}
// Checks parameters in a deferred manner. - Possibly not desired, it's "too" late. I.e.                 // when the    
// result is iterated somewhere in a completely different location in your code the 
// argument passed once will be checked.
IEnumerable<int> GetByReYielding(IEnumerable<int> sequence)
{
    if(null == sequence)
    {
        throw new ArgumentNullException("sequence");
    }

    for(var item in GetIterator()) 
    {
        yield return item;
    }
}

Skeet先生在http://msmvps.com/blogs/jon_skeet/archive/2010/09/03/reimplementing-linq-to-objects-part-2-quot-where-quot.aspx中解释了这个概念。 .Net中提供的标准查询运算符使用非延迟包装函数(例如Where())来检查参数,然后调用核心迭代器函数(正如我在GetByReturn()的实现中所示)。

我希望这有帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM