2009-11-19 152 views
26

有什麼方法可以選擇返回null與「返回yield」驅動迭代器?收益率返回無效

我想在某些情況下返回null,我不認爲這是特定於IEnumerable類型的字符串。謝謝

static void Main(string[] args) 
{ 
    var Items = GetItems(); 

    if (Items != null) 
    { 
     foreach (var item in Items) 
     { 
      Console.WriteLine(item); 
     } 
    } 
    else 
    { 
     Console.WriteLine("<null>"); 
    } 
} 

static IEnumerable<string> GetItems() 
{ 
    if (false) 
    { 
     yield return "Andy"; 
     yield return "Jennifer"; 
    } 

    return null; // <- Compiler Error: 
    // Cannot return a value from an iterator. 
    // Use the yield return statement to return a value, 
    // or yield break to end the iteration. 
} 

回答

34

該(或扔東西一樣立即ArgumentException),你需要你的迭代器分爲兩種方法:

public IEnumerable<string> GetItems() { 
    if (something) return null; 
    return GetItemsInternal(); 
} 

private IEnumerable<string> GetItemsInternal() { 
    // the actual iterator with "yield return" goes here. 
} 
+1

的答案,我問了,但mquander可能發佈一個更正確的做法。 – andleer

26

你沒有使用可用的枚舉(爲了迭代集合中的對象)。如果你想保持你的代碼相似,它現在是什麼,你應該做這樣的事情:

static void Main(string[] args) 
{ 
    var Items = GetItems(); 

    foreach (var item in Items) //this will not enter the loop because there are no items in the Items collection 
    { 
      Console.WriteLine(item); 
    } 

    //if you still need to know if there were items, check the Count() extension method 
    if(Items.Count() == 0) 
    { 
     Console.WriteLine("0 items returned"); 
    } 


} 

static IEnumerable<string> GetItems() 
{ 
    if (false) 
    { 
     yield return "Andy"; 
     yield return "Jennifer"; 
    } 

    yield break; 
} 
6

有沒有辦法在一個迭代方法中返回一個空IEnumerable<T>。您可以在迭代器返回空值而不是空IEnumerable<T>

什麼,你可以,雖然做的是有一個包裝方法,或者返回null或如果你需要的東西像調用到真正的迭代器

static IEnumerable<string> GetItems() { 
    if (false) { 
     return GetItemsCore(); 
    } 
    return null; 
} 

static IEnumerable<string> GetItemsCore() { 
    yield return "Andy"; 
    yield return "Jennifer"; 
} 
12

這恰恰是不鼓勵。當你談論一個序列時,「null」通常應該與「空列表」具有相同的語義。

此外,如果您希望它在沒有額外語法的情況下工作,那麼設計該語言是不可能的,因爲如果您要點擊「yield return [whatever]」,然後點擊「return null?」

+2

我同意,這是一個意圖問題。簡單地通過函數而不觸及'yield return'將產生一個空序列。 Respectibilty檢查是序列空的屬於別的東西。 –

+1

不知道通過生成的空序列。對我來說非常有用的信息。謝謝。 – ryanulit

2

如果合適(當然,枚舉類型必須爲空),沒有什麼能夠阻止您執行yield return null;

+3

如果我從我認爲是IEnumerable中收到null,我會很生氣。是的,你可以在這種情況下使它成爲空字符串,但是爲什麼? – scottm

+0

我沒有說我推薦它,我只是說這是可能的。和btw:一個字符串是一個可以爲空的數據類型... –

+0

我認爲這種方法的一個大問題是沒有一致性。如果某些元素爲空而其他元素具有價值會怎麼樣?這是什麼意思? – andleer

3

雖然yield break是propably最好的答案,它真的並不重要,因爲你總是可以做Items.Count()檢查,如果大於零,甚至做for each on your empty result它事確實有可能的情況下,如果你的結果是空列表或什麼所有,你仍然想要利用收益的力量。

在這種情況下,這將有所幫助。

private IEnumerable<T> YieldItems<T>(IEnumerable<T> items, Action empty = null) 
    { 
     if (items == null) 
     { 
      if (empty != null) empty(); 
      yield break; 
     } 

     foreach (var item in items) 
     { 
      yield return item; 
     } 
    } 

使用

 foreach (var item in YieldItems<string>(null,() => 
     { 
      Console.WriteLine("Empty"); 
     })) 
     { 
      Console.WriteLine(item); 
     }