2013-05-01 89 views
-2

我不得不處理來自我的控制的數據源在我的應用程序中拋出的數據集合。其中一些集合包含空值,我希望在它們打開我的代碼時立即將其過濾掉,而不是將空值檢查代碼散佈到整個地方。我想這樣做在一個可重用的通用方式,並寫了這個方法來做到這一點:刪除集合中的所有空值

public static void RemoveNulls<T>(this IList<T> collection) where T : class 
    { 
     for (var i = 0; i < collection.Count(); i++) 
     { 
      if (collection[i] == null) 
       collection.RemoveAt(i); 
     } 
    } 

我知道在具體List類存在RemoveAll()方法,可以像使用:

collection.RemoveAll(x => x == null); 

但很多返回類型都是基於接口的(IList/IList ...)而不是具體的類型。

+1

請您詳細說明爲什麼不能使用'RemoveAll'? – 2013-05-01 15:21:07

+1

什麼是問題? – 2013-05-01 15:22:04

+2

您編寫的代碼將不起作用,因爲刪除項目會將所有後續元素的索引向下移動1.每次刪除空值時,您的代碼都會跳過檢查下一個元素。 – 2013-05-01 15:25:59

回答

14

,而不是從源集合去除空的,你可以不使用LINQ空創建集合的副本:

collection.Where(i => i != null).ToList(); 

擴展方法將在任何的IEnumerable,包括IList的工作。

+0

爲什麼無用地複製整個集合? – Jammer 2013-05-01 15:30:09

+3

@Jammer,你也可以刪除'.ToList()'部分,這樣它就可以起到過濾器的作用。如果您關心性能,請記住,每個RemoveAt都會移動在刪除之後出現的所有列表項。因此,如果您從1000個項目的列表開始移除10個項目,則至少990個項目將在內存中移動10次。 – alex 2013-05-01 15:33:39

+1

它實際上可以提高性能,因爲從'IList'中移除元素(至少在列表支持爲'List '的情況下)將會強制每次執行時將所有後續元素複製到一個位置。 – 2013-05-01 15:34:57

4

您的方法將不起作用,因爲移除元素將導致所有後續元素的索引遞減。如果你不想要Linq解決方案(這看起來最簡單:看@alex的答案),你應該向後迭代。

public static void RemoveNulls<T>(this IList<T> collection) where T : class 
{ 
    for (var i = collection.Count-1; i >= 0 ; i--) 
    { 
     if (collection[i] == null) 
      collection.RemoveAt(i); 
    } 
} 
+0

在這裏測試它工作得很好。 – Jammer 2013-05-01 15:27:22

+0

更正,你是對的。 – Jammer 2013-05-01 15:30:37

+0

「在此測試它工作得很好」 - 嘗試更多測試用例。具體而言,一個包含兩個連續的空值的集合,後跟一個非空值。 – Joe 2013-05-01 15:30:43