簡體   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