2012-01-08 71 views
2

我發現自己寫之前以下一遍又一遍:檢查空可枚舉循環

if (myEnumerable != null) { 
    foreach (var element in myEnumerable) { 
     DoSomething(element); 
    } 
} 

這是乏味我想列舉每次檢查NULL,有沒有更好的辦法?例如,是否有一種方法來重寫枚舉器返回「Enumerable.Empty」而不是NULL?

+0

更好的是什麼意思?我沒有看到你在這裏想要改進的東西。 – Tudor 2012-01-08 20:03:35

+0

爲什麼你經常首先迭代潛在的空序列?我幾乎從不需要在循環之前檢查null,因爲在大多數情況下,'null'首先是我的函數的一個無效參數,並且經過驗證。 – CodesInChaos 2012-01-08 20:05:20

回答

6

那麼,理想的設計你的代碼,以便它不能爲空。另外,創建一個擴展方法:

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

然後:

foreach (var element in myEnumerable.EmptyIfNull()) 
    DoSomething(element); 
} 

這是大致相同Darin的做法,但空合併運算符移動到一個擴展方法。

+1

T中的T是什麼EmptyArray = ...? – dtb 2012-01-08 20:04:52

+0

@dtb:嘎,你說得對。編輯... – 2012-01-08 20:05:13

+0

當然,如果您所使用的序列的靜態類型與「IEnumerable 」不同,這會顯着降低枚舉速度。 – CodesInChaos 2012-01-08 20:07:04

8

您可以使用null-coalescing operator

foreach (var element in myEnumerable ?? Enumerable.Empty<Foo>()) { 
    DoSomething(element); 
} 

,但更好的方法是確保您隨時隨地都取這個IEnumerable<T>從不會返回null這是傳統的方式,在.NET可枚舉工作。

+0

非常好的建議。我們可以更進一步:你認爲我們可以重寫枚舉器並返回「空」而不是null? – desautelsj 2012-01-08 20:04:39

+2

@desautelsj,不,對我來說,更進一步的是修復返回這個枚舉的代碼,以便它永遠不會返回null。 – 2012-01-08 20:06:09

+0

@desautelsj:重寫*哪個*枚舉器?你正在談論一個變量,它是以null開頭的 - 你只能調用除擴展方法之外的其他任何東西。我們不知道什麼是返回空引用開始。 – 2012-01-08 20:06:13

1

擴展方法:

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

然後,你可以做

foreach (var element in myEnumerable.EmptyIfNull()) 
{ 
    DoSomething(element); 
} 
0

不幸的是檢查null是生活中的事實......但它可以更容易。我已經寫了一個名爲ValidWithItems的擴展來檢查null以及在非null時有佔位項,以便實際枚舉項。

public static class EnumerableExtensions 
{ 

    /// <summary>Does two checks, if not null and if it has items.</summary> 
    /// <returns>True if it is not null and has at least 1 item.</returns> 
    public static bool ValidWithItems<T>(this IEnumerable<T> target) 
    { 
     return ((target != null) && (target.Any())); 
    } 
}