2011-08-30 31 views
20

已有question on SO about "possible multiple enumerations",但此問題更具體。即使「IsNullOrEmpty」檢查也給出了「IEnumerable可能的多次枚舉」警告

請考慮以下的方法,這需要一個IEnumerable<string>作爲輸入,並針對它的每個元素執行一個給定的方法:

public static bool SomeMethod(IEnumerable<string> enumerable) 
{ 
    if (enumerable.IsNullOrEmpty()) 
    { 
     // throw exception. 
    } 
    else 
    { 
     return (enumerable.All(SomeBooleanMethod)); 
    } 
} 

在上面的代碼,IsNullOrEmpty只是它運行

擴展方法
return (!ReferenceEquals(enumerable, null) || enumerable.Any()); 

問題是ReSharper警告我有關「IEnumerable可能的多個枚舉」,我真的不知道這是否真的可能是一個問題。

我明白警告的意思,但是如果您確實需要在無效或空白的情況下檢查並拋出異常,您可以在這種情況下真正做什麼?

+0

爲什麼你要這個方法拋出,如果通過一個空序列? 「爲這個(空)序列的每個成員做些什麼」的語義是非常明顯的,不是嗎?另外,爲什麼使用'ReferenceEquals()'而不是'== null'有什麼特別的理由? – AakashM

+0

它確實不是,但現在想象這是一個構造函數。如果我不能從空序列構造一個對象,我不應該拋出一個exceptio? – User

+1

當然,如果你真的沒有什麼可以做的;但是*一般來說*我會說空序列應該和任何非空序列一樣好。例如,List <>'非常樂意從空序列構造。當然,我只是泛泛而談,你知道你的情況*的細節*。 – AakashM

回答

30

這意味着您(部分)在IEnumerable上多次迭代:首先在調用Any()(需要至少初始化迭代以查看枚舉是否返回任何元素)以及第二次All(從頭開始迭代)。

ReSharper警告你這個問題的原因是枚舉枚舉可能會導致副作用,並且無意中迭代兩次可能會觸發副作用兩次,這可能會或可能不需要。

+0

可否請您解釋副作用或任何例子都會令人愉快。 –

+12

例如,您的枚舉可以從網絡流中讀取字節(這會構成副作用)。如果您枚舉一次,一切正常,並且流一開始就一次讀完。但是,如果您中止第一次迭代,然後再次迭代,即使底層網絡流無法向後尋找,您很可能會收到不良行爲。 – tdammers

+0

感謝您的示例 –

8

由於@tdammers標識,所指的「多個枚舉」是AnyAll所要求的兩個枚舉。既然你想拒絕一個空的序列,我能想到的最好的是:

public static bool SomeMethod(IEnumerable<string> enumerable) 
{ 
    if (enumerable == null) 
     throw new ArgumentNullException(); 

    // Manually perform an All, keeping track of if there are any elements 
    bool anyElements = false; 

    bool result = true; 

    foreach (string item in enumerable) 
    { 
     anyElements = true; 
     result = result && SomeBooleanMethod(item); 

     // Can short-circuit here 
     if (!result) 
      break; 
    } 

    if (!anyElements) 
     throw new ArgumentException(); // Empty sequence is invalid argument 

    return result; 
} 
+1

Upvoting努力。 –