上一个建议中提到了foreach的两个优点:语法更简单,默认调用Dispose方法,所有我们强烈建议在实际的代码编写中更多的使用foreach。但是,该建议也有不适合的场景。
foreach存在一个问题:它不支持循环时对集合进行增删操作。比如,运行下面代码会抛出异常InvalidOperationException:
List<int> list=new List<int>(){0,1,2,3};
foreach (int item in list)
{
list.Remove(item);
Console.WriteLine(item);
}
取而代之的方法是使用for循环:
for (int i = 0; i < list.Count; i++)
{
list.Remove(list[i]);
Console.WriteLine(list[i]);
}
foreach循环使用了迭代器进行集合的遍历,它在FCL提供的迭代器内部维护了一个对集合版本的控制。那么什么是集合版本?简单来说,其实它就是一个整形的变量,任何对集合的增删操作都会使版本号加1。foreach会调用MoveNext方法来遍历元素,在MoveNext方法内部会进行版本号的检测,一旦检测到版本号有变动,就会抛出InvalidOperationException异常。
如果使用for循环就不会带来这样的问题。for直接使用索引器,它不对集合版本号进行判断,所以不会存在以为集合的变动而带来的异常(当然,超出索引长度这种异常情况除外)。
for循环和foreach循环实现上有所不同(前者索引器,后者迭代器)。