2013-05-01 139 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