相信小伙伴们在开发过程中都遇到过System.InvalidOperationException:“集合已修改;可能无法执行枚举操作。”。
如下图所示:
那foreach是如何检测到数据被修改的呢?
通过浏览源码发现,C#的集合类都包含类似这样的代码:
public class Set {
private int m_version;
public void Add(T item) {
// 添加一个元素到集合...
m_version++;
}
public void Remove(T item) {
// 从集合中移除一个元素...
m_version++;
}
}
集合内有一个名为m_version的私有变量,每次修改集合数据,m_version的值就加一。
foreach遍历操作实际上是在访问集合的迭代器,每个集合类型都有一个迭代器类型,我们来看迭代器的实现:
public struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator {
private int version;
internal Enumerator(Set set) {
version = set.m_version;
}
public bool MoveNext() {
if (version != set.m_version) {
throw new InvalidOperationException();
}
// 省略代码...
}
void System.Collections.IEnumerator.Reset() {
if (version != set.m_version) {
throw new InvalidOperationException();
}
// 省略代码...
}
// 其他的方法省略...
}
可见在foreach循环的时候,迭代器一旦检测到m_version的值不等于初始值,就会抛出InvalidOperationException异常