2016-01-07 45 views
3

假設空值和空集合是等價的,我試圖編寫IEnumerable類型的擴展方法來返回派生類型的空集合而不是null。通過這種方式,我不必在所有地方重複執行空值檢查,並且我不會收到必須投出的IEnumerable。C#EmptyIfNull擴展任何IEnumerable返回空派生類型

例如

List<Foo> MethodReturningFooList() 
{ 
... 
} 

Foo[] MethodReturningFooArray() 
{ 
... 
} 

void Bar() 
{ 
    List<Foo> list = MethodReturningFooList().EmptyIfNull(); 
    Foo[] arr = MethodReturningFooArray().EmptyIfNull(); 
} 

public static class Extension 
{ 
    public static T EmptyIfNull<T>(this T iEnumerable) 
     where T : IEnumerable, new() 
    { 
     var newTypeFunc = Expression.Lambda<Func<T>>(Expression.New(typeof(T))).Compile(); 
     return iEnumerable == null ? newTypeFunc() : iEnumerable; 
    } 
} 

此擴展似乎工作,但沒有人看到任何陷阱?

+0

Returnin默認() – Totodile

+0

IEnumerable和IEnumerable的是不一樣的東西。 –

+0

每次調用'EmptyIfNull'時,都會編譯一個新方法。你可以簡單地執行'return iEnumerable == null? Activator.CreateInstance ():iEnumerable;' – Rob

回答

5

是的,它會在這種情況下打破:

IEnumerable<int> test = null; 
var result = test.EmptyIfNull(); 

你能解決嗎像這樣:

public static class Extension 
{ 
    public static List<T> EmptyIfNull<T>(this List<T> list) 
    { 
     return list ?? new List<T>(); 
    } 
    public static T[] EmptyIfNull<T>(this T[] arr) 
    { 
     return arr ?? new T[0]; 
    } 
    public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> enumerable) 
    { 
     return enumerable ?? Enumerable.Empty<T>(); 
    } 
} 

您需要重載以確保您返回的是相同的集合類型(與以前相同)。

這裏有一個情況的一個例子是不能工作通過返回相同的集合類型:

public abstract class MyAbstractClass : IEnumerable<int> 
{ 
    private List<int> tempList = new List<int>(); 
    public IEnumerator GetEnumerator() 
    { 
     return tempList.GetEnumerator(); 
    } 
    IEnumerator<int> IEnumerable<int>.GetEnumerator() 
    { 
     return tempList.GetEnumerator(); 
    } 
} 

MyAbstractClass myClass = null; 
MyAbstractClass instance = myClass.EmptyIfNull(); 

有沒有辦法,我們可以回到這裏MyAbstractClass不知道有關的子類。沒有參考的話,這是不可能的,沒有猜測。此外,當類沒有默認構造函數時會發生什麼?進入危險的領域。

你需要要麼有一個包羅萬象的IEnumerable<T>回報,並讓用戶將其丟,或者提供過載正如我以上

+0

如果變量爲空,代碼不會中斷,他首先檢查變量是否爲空。 –

+3

@AlbertoMonteiro不,它打破,因爲類型是'IEnumerable '並且不能構造 – Rob

+0

是的,忘記了這個細節。 –

4

我只是要改善這種像

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

或者更好地與C#6

public static class Extension 
{ 
    public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> iEnumerable) 
     => iEnumerable ?? Enumerable.Empty<T>(); 
} 
+2

'T'已經是集合。所以如果你用'int []'調用它,這將會返回一個'List '。你只需要返回'Activator.CreateInstance ();' – Rob

+0

@Rob謝謝我修正 –

+1

請注意,作爲[羅布的答案](http://stackoverflow.com/a/34646103/477420)顯示此代碼是非常不同OP的一個 - 它只適用於'IEnumerable '(這實際上是大部分代碼應該使用的),但是在保存集合類型的帖子中顯示的測試用例失敗(這是否是好主意可能是單獨的討論)。 –

0

,我得到一個泛型參數的方法所示(與限制是一個類,因爲我將創建這種類型的實例)。然後,我在運行時定義一個默認對象,並檢查參數接收的對象是否爲null,如果對象爲null,則返回在運行時實例化的對象,否則返回通過參數傳遞的對象本身。

我希望幫助

public static T EmptyIfNull<T>(this T obj) where T : class 
    {   
     var objNotNull = Activator.CreateInstance(typeof(T)); 

     if (obj == null) 
      return objNotNull as T; 

     return obj; 
    } 

單元測試:

enter image description here

+0

添加一些解釋和回答這個答案如何幫助OP在解決當前問題 –