使用C# Linq
的确给我们带来了很多的方便,但是如果不合理使用,会造成一些隐藏的bug,而且很难被发现。
今天我就分享一个工作中遇到的问题。
需求:对list
进行遍历,把满足某一条件的item Remove
掉。
List<ClassA> list = new List<ClassA>();
for (int i = 0; i < 1000; i++)
{
list.Add(new ClassA());
}
il.ForEach(x => il.Remove(x));
为了简化代码,在此不加条件语句。
以上代码貌似是把list
中所有的item
都Remove
掉,但其实不然。
可以看到在执行完ForEach
之后list
中还有500项。
想必高手们应该之后了吧?在对list
进行删除的时候,list
整个集合的index
已经发生了变化。
Remove
一次,原来集合的index
就会整体向前移动一个。
原index
:
3,4,5,6
Remove()
后
index
:
2,3,4,5
其实以上代码等价于:
List<IA> list = new List<IA>();
for (int i = 0; i < 1000; i++)
{
list.Add(new ClassA());
}
for (int i = 0; i < 500; i++)
{
list.Remove(list[i]);
}
所以大家应该知道什么原因了吧?
所以应对以上bug
,并且使用简介的Linq
,正确的办法是:
for (int i = 0; i <list.Count; i++)
{
if (list[i].a==0)
{
list.RemoveAt(i);
i--;
}
}
list.ToList().ForEach(x => {
if (x.a==0)
{
list.Remove(x);
}
});
ToList()
会new
一个list
,然后对新的list
进行遍历,删除旧list
中与之对应index
的值,至少这样的写法是对的。但是最优的办法是使用List<T>
中的RemoveAll(Predicate<T> match)
方法,该方法还会return
被删除的items
的个数。
list.RemoveAll(x => x.a == 0);