我们先来看看ReversibleSortedList
类的定义:s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
public class ReversibleSortedList :s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
IDictionary, ICollection>,s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
IEnumerable>, IDictionary, ICollection, IEnumerable
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·s<¦Þã}æwww.netcsharp.cnmåÑþ{G · 它一共实现了6
个接口。但从本质上来说,实现IDictionary<TKey, TValue>
接口和IDictionary
接口就等同于实现了以上6
个接口。因为IDictionary<TKey, TValue>
继承自ICollection<KeyValuePair<TKey, TValue>>
和IEnumerable<KeyValuePair<TKey, TValue>>
接口,而IDictionary
接口继承自ICollection
和IEnumerable
接口。下面我们来看一下这些接口的关系图:s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·图2 s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
ReversibleSortedList类接口关系图
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·其实ReversibleSortedList
类的大部份代码都用于实现左边这两个接口,看到这张图你应该理解了为什么会需要1300
行的代码。为了一步一步地实现这个类,我们需要首先实现底层接口,由于ICollection
接口本身就继承自IEnumerable
接口,所以首先应该实现的是IEnumerable
接口。从前面一节可以知道IEnumerable
接口的实现需要一个嵌套类,它返回一个枚举器。我们可以为IDictionary<TKey, TValue>
接口和IDictionary
接口实现同一个枚举器,只要这个枚举器实现了IEnumerator<KeyValuePair<K, V>>
接口和IDictionaryEnumerator
接口就可以了。前者是IDictionary<TKey, TValue>
接口所需要的枚举器,后者是IDictionary
接口所需要的枚举器(见前一节)。下面是我们的这个枚举器所需实现的接口的关系图:s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
图3 s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
Enumerator<K, V>类接口关系图
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
实现这个类需要注意一个问题,在ReversibleSortedList类中添加了一个新的成员变量:version。在插入元素时(insert方法)会更改这个version值,表示类中的元素已经进行了改动。为什么要使用它呢?在此我做些推测。从MSDN中或许可以找到线索。我们在MSDN找到关于Dictionary<TKey, TValue>类的介绍,这个类跟ReversibleSortedList类非常相似。在关于它的线程安全中有这么一段话:s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
此类型的公共静态成员是线程安全的。但不能保证任何实例成员是线程安全的。s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
只要不修改该集合,Dictionary<(Of <(TKey, TValue>)>) 就可以同时支持多个阅读器。s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
即便如此,从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。当出现枚举与写访问互相争用这种极少发生的情况时,必须在整个枚举过程中锁定集合。若要允许多个线程访问集合以进行读写操作,则必须实现自己的同步。s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
可以推测,version用于在枚举过程中判断是否有其他线程更改了ReversibleSortedList实例中存储的元素,以便弹出异常。这一点可以在稍后的代码中看见。s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
这时可能有人会问了,前面一节中关没有这种判断啊?好,让我们看看上一节关于IDictionary接口的代码。在它的实现枚举器的嵌套类SimpleDictionaryEnumerator中,看看它的构造方法s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
public SimpleDictionaryEnumerator(SimpleDictionary sd)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
items = new DictionaryEntry[sd.Count];s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
Array.Copy(sd.items, 0, items, 0, sd.Count);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
:s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
从代码中可以看出,它把外部类中的所有元素拷贝到另一块内存中进行枚举,这样在多线程访问集合时自然不会出错,但如果集合中的元素很多就会带来性能上的损失。而我们实现的ReversibleSortedList类将直接使用集合中的元素进行枚举,所以需要使用version来保证在出错时可以弹出异常。s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
下面我们在“ReversibleSortedList 0.3版本”的基础上继续构建。关于version的代码这里不再讲解,请大家查看稍后完整的0.4版本的代码。首先添加一个实现枚举s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
private struct Enumerator : IEnumerator>, IDisposable,s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
IDictionaryEnumerator, IEnumerators<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
private ReversibleSortedList _ReversibleSortedList;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
private K key;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
private V value;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
private int index;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
private int version;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
internal Enumerator(ReversibleSortedList ReversibleSortedList)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{ //获取外部类中的元素引用,以对它进行枚举s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this._ReversibleSortedList = ReversibleSortedList;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.index = 0;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.version = this._ReversibleSortedList.version;//记录外部类版本号s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
//设置键和值为其默认类型,请参考:s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
//http://cgbluesky.blog.163.com/blog/static/2412355820081695340822/s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.key = default(K); s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.value = default(V);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
public void Dispose()s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.index = 0;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.key = default(K);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.value = default(V);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
object IDictionaryEnumerator.Keys<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
gets<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
if ((this.index == 0) ||s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
(this.index == (this._ReversibleSortedList.Count + 1)))s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
throw new InvalidOperationException(s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
"不能进行枚举操作.");s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
return this.key;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
public bool MoveNext()s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
if (this.version != this._ReversibleSortedList.version)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{ //版本检查s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
throw new InvalidOperationException("枚举版本检查失败!");s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
if (this.index < this._ReversibleSortedList.Count)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.key = this._ReversibleSortedList.keys[this.index];s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.value = this._ReversibleSortedList.values[this.index];s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.index++;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
return true;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.index = this._ReversibleSortedList.Count + 1;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.key = default(K);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.value = default(V);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
return false;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
DictionaryEntry IDictionaryEnumerator.Entrys<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
gets<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
if ((this.index == 0) ||s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
(this.index == (this._ReversibleSortedList.Count + 1)))s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
throw new InvalidOperationException("不能进行枚举操作.");s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
return new DictionaryEntry(this.key, this.value);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
public KeyValuePair Currents<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
gets<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
return new KeyValuePair(this.key, this.value);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
object IEnumerator.Currents<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
gets<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
if ((this.index == 0) ||s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
(this.index == (this._ReversibleSortedList.Count + 1)))s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
throw new InvalidOperationException("不能进行枚举操作");s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
return new DictionaryEntry(this.key, this.value);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
object IDictionaryEnumerator.Values<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
gets<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
if ((this.index == 0) ||s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
(this.index == (this._ReversibleSortedList.Count + 1)))s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
throw new InvalidOperationException("不能进行枚举操作");s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
return this.value;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
void IEnumerator.Reset()s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
if (this.version != this._ReversibleSortedList.version)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
throw new InvalidOperationException("枚举版本检查失败!");s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.index = 0;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.key = default(K);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
this.value = default(V);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
器的嵌套类:s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
这个嵌套类的代码对照图3很容易看懂,每个方法的功能在MSDN中也有详细的介绍,这里不再对它进行讲解。接下来要给外部类实现IEnumerable<KeyValuePair<TKey, TValue>>和 IEnumerable接口。更改类声明代码如下:s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
public class ReversibleSortedList :s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
IEnumerable>, IEnumerable
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
当然,这两个接口分别只有一个成员:GetEnumerator()方法,刚才所创建的嵌套类就是为这个方法所创建的。接下来在ReversibleSortedList类中使用显式接口成员实现来实现这两个接口:s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
IEnumerator>s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
IEnumerable>.GetEnumerator()s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
return new Enumerator(this);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
IEnumerator IEnumerable.GetEnumerator()s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
return new Enumerator(this);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
好,现在更改Main()方法中的代码看看是否可以使用foreach循环来访问ReversibleSortedList中的元素,当然,前面所写的Print()成员方法可以退休了。s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
static void Main()s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
ReversibleSortedList rs=new ReversibleSortedList();s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
rs.Add(3,"a");s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
rs.Add(1,"b");s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
rs.Add(2,"c");s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
rs.Add(6,"d");s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
rs.Add(5,"e");s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
rs.Add(4,"f");s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
foreach (KeyValuePair d in rs)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
{s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
Console.WriteLine(d.Key + " " + d.Value);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
}
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
运行结果:s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
1s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
bs<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
2s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
cs<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
3s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
as<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
4s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
fs<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
5s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
es<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
6s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
ds<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
真棒,现在已经取得了阶段性的成果。但还有一些遗憾,虽然在Enumerator类中实现了IDictionaryEnumerator接口,但还不能在foreach中使用DictionaryEntry访问元素。这是因为IDictionary接口重载了GetEnumerator()接口,而它返回的是一个IDictionaryEnumerator接口,也就是说,只有实现了IDictionary接口才能使用DictionaryEntry访问其中元素。实现IDictionary接口之前我们需要建立一些辅助的内部类,这将在下一节进行讲解。s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·附件:
reversiblesortedlist0.4.rar