.Net编程接口剖析系列之迭代器
Version控制
我们来看看这段代码,它想把列表中的所有负数给删除掉。
List<int> list=new List<int>();这段代码看起来似乎写的没有问题,编译也能通过。但是真正跑起来就会抛出异常了。它将会抛出一个InvalidOperationException,错误信息是"Collection was modified; enumeration operation may not execute."。
list.Add(0);
list.Add(-1);
list.Add(2);
foreach(int i in list)
{
if(i<0) list.Remove(i);
}
怎么会这样呢?原来是微软在定义迭代器功能的时候,要求在枚举开始到结束的这个过程之中,应该要求保证被枚举的对象不能够增加或者减少元素。其实这个需求也很好理解,相信谁也不想在清点队伍人数的时候,队伍里面的人还在出出进进吧?
这里善于思考的读者可能马上会想到一个问题,迭代器又是如何知道这个集合发生改变了呢?这里微软用了一个简单而巧妙的办法,给集合对象设置了一个版本信息,通过在迭代过程中不断检查版本信息,来判断集合对象是否已经被更新。具体的做法如下。
1. 给集合对象增加一个成员private int _version,初始值设置为0;
2. 在所有直接对集合元素进行更新的操作中,例如insert、remove等等,都将_version ++;
3. Enumerator也设置一个_version成员,并且在构造函数中将其设置为集合对象的_version成员。其实也就是记录了collection当时的版本。
4. Enumerator在迭代的过程中,不断检查collection的_version字段,一旦发现与当初记录的_version值不同,则认定为集合已经被更新,立即抛出异常。
一点感言
从foreach到yield return还有C#3.X的LINQ等等,我们发现C#正在为我们越来越多的事情,但是我们不知道这种变化何时是尽头,也不知道我们的学习何时是尽头。C#引入这些新特性是希望不断简化我们的编码工作,但是与此同时难免也会带来一些新的问题,那就是C#正在变得越来越庞大和复杂,也许有一天我们会发现,自己都不知道什么是C#了,也许把什么都做入语言层面并非是一件好事。天天有新技术的感觉是不错,不过昨天的新技术在今天立马就变成了旧技术却可能是一件令人沮丧的事情。我们需要创新,但是更加需要经典,C#何时才能成为经典?
0
相关文章