2010-08-19 58 views
12

我累了使用這樣的代碼的計數():返回零對零IEnumerables

var count = 0; 
if (myEnumerable != null) 
{ 
    count = myEnumerable.Count(); 
} 

這是一個有點迂腐:

var count = (myEnumerable ?? new string[0]).Count(); 

是否有任何有條理的方式這樣做?我曾經在IEnumerable <>上使用過一個(命名不正確)的PhantomCount擴展方法,它使用我的第一個代碼示例,但它有一些關於它的氣味(除了名稱)。

回答

30

的問題是真正無論是創建這些可枚舉。除非你有一個很好的理由,否則生成一個可迭代集合的東西應該返回一個空集合而不是null。這將與Null-Object-Pattern一致,因此好處是相同的。

我的建議是解決什麼生產myEnumerable,或者如果你不能做到這一點,添加一個檢查方式早些時候,看它是否是零和作出適當的反應。

+12

用於診斷根本原因的+1 – cordialgerm 2010-08-19 08:31:37

+0

有另一個+1。設計一個API來返回空集合而不是空值是非常好的做法,這樣可以避免開發人員一直在做這樣的測試。 – uriDium 2010-08-19 08:58:18

+0

取決於。在愛爾蘭製作的所有非常好的葡萄酒(這是一份空白的名單)和納尼亞製造的所有非常好的葡萄酒之間存在差異(由於納尼亞不存在,因此無效)。有時需要區分空和空。我同意一個人應該傾向於迴歸空虛。 – 2010-08-19 10:12:04

13

如何

count = myEnumerable == null? 0 : myEnumerable.Count() 
+1

我有一種感覺,HES要問比這更整潔,+1沒有少:) – VoodooChild 2010-08-19 08:27:23

+0

你的感覺是正確的,但它是一個很好的答案呢。 – ProfK 2010-08-19 09:01:46

9

我不認爲使用擴展方法是一個壞主意。

public static int NullableCount<T>(this IEnumerable<T> collection) 
{ 
    return collection == null ? 0 : collection.Count(); 
} 
+1

+1我做了完全相同的事情 - 只是將它命名爲「CountOrZero」。我個人認爲它更清楚。 – 2010-08-19 08:30:51

2

只要創建自己的擴展方法,可以根據需要處理null枚舉類型。

public int CountOrNull<T>(this IEnumerable<T> source) 
{ 
    return source == null ? 0 : source.Count(); 
} 

然後,您可以簡單地使用:

var list1 = new int[] { 1, 2, 3, 4 }; 
var list2 = (int[])null; 

var count1 = list1.CountOrNull(); // 4 
var count2 = list2.CountOrNull(); // 0 

這是對擴展方法偉大的事情。即使調用方法的對象(您似乎是)調用方法爲null,它們仍然可以正常工作。

+0

_ @ Noldorin:_修正了代碼示例中的錯字(「// 4」註釋);也許可以證實這確實是你的意圖。 – stakx 2010-08-19 08:56:10

+0

@stakx:謝謝;這確實是一個錯字。 – Noldorin 2010-08-19 09:00:23

2

我也寫我自己的擴展方法CountOrZeroForNull,如其他答案所示。

除了...而不是:

var count = (myEnumerable ?? new string[0]).Count(); 
          // ^^^^^^^^^^^^^ 

你可以寫:

var count = (myEnumerable ?? Enumerable.Empty<string>()).Count(); 
          // ^^^^^^^^^^^^^^^^^^^^^^^^^^ 

這不會減輕你的具體問題,但它繞過一個未使用的陣列分配。 (Enumerable.Empty<T>作爲一個簡單的yield break聲明最有可能實現的。)

+0

'Enumerable.Empty '的當前實現實際上返回一個單獨的空'T []'數組。 – LukeH 2010-08-19 08:47:55

+0

_ @ LukeH:_我不會這麼想的。謝謝你看這個。 – stakx 2010-08-19 08:52:04

-2
var count = 0; 

if (myEnumerable != null) 
    count = myEnumerable.Count(); 

雖然它並不像技術作爲其他的答案,這是迄今爲止最可讀。

+2

我不認爲這三行比一個有名的擴展方法更具可讀性。 – Lee 2010-08-19 08:48:21

+0

是的,我想避免重複幾次相同的檢查。畢竟,這是我的問題。 – ProfK 2010-08-19 09:07:18

+1

嘿,也許看了這個問題? – 2010-08-19 09:08:46

1

如果返回的值是0,您會採取什麼操作?

如果這就是很有趣,也許你應該使用哈克的IsNullOrEmpty擴展方法爲IEnumerable像這樣:

public static bool IsNullOrEmpty<T>(this IEnumerable<T> items) 
{ 
    return items == null || !items.Any(); 
} 

的聯繫是http://haacked.com/archive/2010/06/10/checking-for-empty-enumerations.aspx

發佈的博客上的評論,您還會發現一個Exception類我寫信去:

public class ArgumentNullOrEmptyException : ArgumentNullException 
{ 
    public ArgumentNullOrEmptyException(string paramName) : base(paramName) 
    {} 

    public ArgumentNullOrEmptyException(string paramName, string message) : base(paramName, message) 
    {} 

    public override string Message 
    { 
     get 
     { 
      return "Value cannot be null nor empty.{0}Parameter name: {1}".FormatWith(Environment.NewLine, ParamName); 
     } 
    } 
} 
5

我使用自定義extensi在方法:

public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> source) 
{ 
    return source ?? Enumerable.Empty<T>(); 
} 

... 

int count = myEnumerable.EmptyIfNull().Count(); 
+0

+1,我認爲這是所列擴展方法解決方案中最乾淨的。非常明確的是,你假設一個空的枚舉只是空的,之後你可以照常使用枚舉。 – 2010-08-19 15:15:53