什么是遍历List<T>并删除不需要对象的最简单方法?

8
在我的应用程序中,_collection是一个列表,我需要从其中移除所有不符合条件的User对象。但是,以下代码在第二次迭代时会出现无效操作错误,因为_collection本身已经被改变:
foreach (User user in _collection)
{
    if (!user.IsApproved())
    {
        _collection.Remove(user);
    }
}

我可以创建另一个列表集合并来回复制它们,但这样就会出现非克隆引用类型等问题。

有没有一种比将 _collection 复制到另一个列表变量更简洁的方法?

3个回答

54
_collection.RemoveAll(user => !user.IsApproved());

如果您仍在使用2.0版本:

_collection.RemoveAll(delegate(User u) { return !u.IsApproved(); });

顺便提一下,如果您不想操作原始列表,可以使用以下方式获取另一个已批准用户列表:

_collection.FindAll(user => user.IsApproved());

或者使用 _collection.FindAll(user => user.IsApproved()); 来消除否定语。 - Ionuț G. Stan
collection.FindAll会返回另一个集合。这与更改初始集合非常不同(可能存在某些其他对象持有对同一列表的引用,您需要更改该列表而不是创建另一个列表)。 - Mehrdad Afshari

4
您可以始终从顶部索引开始,向下迭代到0:
for (int i = _collection.Count - 1; i >= 0; i--)
{
    User user = _collection[i];
    if (!user.IsApproved())
    {
        _collection.RemoveAt(i);
    }
}

Mehrdad的答案看起来非常优雅。


这似乎包含一个错误。考虑一个包含两个元素的集合,第一个元素未被批准。第一个元素被移除后,collection[1]就会越界。 - Steven Sudit
Steven:根据您所描述的情况,上述代码已经检查了collection[1](在删除collection[0]后变为collection[0]),因为它是从头到尾迭代的。因此不应该出现任何越界错误。 - Dan Tao
没关系。再仔细看一遍,你会发现没问题的。 - Clinton Pierce
对于我们这些仍在使用.NET 2.0的人来说,这种方法是最好的选择。 - C-Pound Guru
1
@C-Pound Guru:List<T>.RemoveAll自2.0版本就已经存在了:list.RemoveAll(delegate(User u) { return !u.IsApproved(); }); - Mehrdad Afshari

0
无论何时,在循环中有可能修改集合,请选择使用for循环。Mehrdad提供的解决方案非常好,值得一试!
以下是我在处理可修改集合时发现有用的代码:
for(int index=0;index < _collection.Count; index++)
{
    if (!_collection[index].IsApproved)
    {
        _collection.RemoveAt(index);
        index--;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接