构建可反转排序的泛型字典类(4)--IDictionary接口

 

C#对集合类型有统一的规范。它的好处不言而喻,所有集合类都有一些统一的调用方法和属性,这使得学习成本大大降低。统一的规范就是通过接口来实现的(关于接口,如果不熟,请参考

http://www.enet.com.cn/eschool/video/c/30.shtml ),另一方面一些类也会直接调用这些标准接口,使得我们写出来的类有更好的兼容性。最典型的例子莫过于IEnumerable接口,只要实现了它就可以使用foreach语句进行调用。

我们将要给ReversibleSortedList实现的是IDictionary接口,先来看看它的定义:

public interface IDictionary : ICollection, IEnumerable

ICollection接口是所有集合类的基接口,FCL中所有集合,不管是哪种方式的集合都实现它。IEnumerable接口则是枚举器接口,实现了它就可以使用foreach语句对它进行访问。IDictionary接口则继承自这两个接口,它表示键/值对的非通用集合。

ICollection接口的定义为:

public interface ICollection : IEnumerable

从这个定义可以看出,所有集合类都应该支持foreach语句进行访问。

1列出了各个接口的成员

接口

成员

说明

ICollection

Count属性

获取 ICollection 中包含的元素数

IsSynchronized属性

获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)

SyncRoot属性

获取可用于同步 ICollection 访问的对象

CopyTo方法

从特定的 Array 索引处开始,将 ICollection 的元素复制到一个 Array

IEnumerable

GetEnumerator方法

返回一个循环访问集合的枚举器

IDictionary

IsFixedSize属性

获取一个值,该值指示 IDictionary 对象是否具有固定大小

IsReadOnly属性

获取一个值,该值指示 IDictionary 对象是否为只读

Item属性

获取或设置具有指定键的元素

Keys属性

获取 ICollection 对象,它包含 IDictionary 对象的键

Values属性

获取 ICollection 对象,它包含 IDictionary 对象中的值

Add方法

IDictionary 对象中添加一个带有所提供的键和值的元素

Clear方法

IDictionary 对象中移除所有元素

Contains方法

确定 IDictionary 对象是否包含具有指定键的元素

GetEnumerator方法

返回一个用于 IDictionary 对象的 IDictionaryEnumerator 对象

Remove方法

IDictionary 对象中移除带有指定键的元素

从上表可以看出,实现IDictionary接口并不简单。我个人喜欢先把复杂的问题简单化,但所要实现的东西实在太多,只能尽力而为。如果在我们之前所构建的ReversibleSortedList类中加上这么代码将不利于理解如何实现IDictionary接口。所以我从MSDNcopy了一段IDictionary接口实现的代码,并把所有属于出错判断的部分咔嚓掉,先让大家对IDictionary接口有个了解后再给ReversibleSortedList类实现它。

实现这个接口需要注意以下几点:

1.         IEnumerable接口的GetEnumerator方法的实现,这个方法的原型为:

IEnumerator GetEnumerator()

也就是说这个方法返回的是一个实现了IEnumerator的类,IEnumerator接口的成员如下:

Current属性:获取集合中的当前元素

MoveNext方法:将枚举数推进到集合的下一个元素

Reset方法:将枚举数设置为其初始位置,该位置位于集合中第一个元素之前

实现了IEnumerator接口的类可以通过一个内部类来实现,又要多实现三个成员,事态变得进一步复杂。关于IEnumerable接口实现,如果不懂可以上网搜搜,能搜一大箩筐出来,也可以参考设计模式中的“Iterator 迭代器模式”进行学习。

IDictionary接口中有自己的GetEnumerator方法,它返回的IEnumerator接口的子接口:IDictionaryEnumerator接口。这个接口的定义为:

public interface IDictionaryEnumerator : IEnumerator

它的成员为:

Entry:同时获取当前字典项的键和值

Key:获取当前字典项的键

Value:获取当前字典项的值

这意味着除了要实现IEnumerable接口的三个成员外,还要实现它自己的三个成员,变得更复杂了,晕!值得庆幸的是由于IDictionaryEnumerator接口继承自IEnumerator接口,可以把IDictionaryEnumerator接口强制转换为IEnumerator接口用于实现IEnumerable接口的GetEnumerator方法。当然,由于两个方法同名,只能给IEnumerable接口用显示接口成员实现了。

2.         Item属性,这个属性并不是叫你实现了个名字叫“Item”的属性,而是一个索引器,通过实例名加方括号中的索引来访问集合里的元素。关于索引器,如果不熟,请参考:

http://www.enet.com.cn/eschool/video/c/20.shtml

3.         Keys属性,这个属性的原型为:

ICollection Keys { get; }

也就是说,它返回一个实现了ICollection接口的类。ICollection接口前面已经讲过,C#中的所有集合类都实现了它。本例中这个属性返回的是一个数组,因为数组也实现了ICollection接口。另外Values属性也是同样的情况。

4.         本例中,字典集合里的一个元素是由键和值组成的,这一个元素使用了FCL中现成的DictionaryEntry来实现,它定义了可设置或检索的字典键/值对。

下面列出了代码,请大家参照注释进行理解。

IDictionary接口的实现(以下代码可直接拷贝并运行)

using System;
using System.Collections;

public class SimpleDictionary : IDictionary
{
    
private DictionaryEntry[] items; //用数组存放元素
    private Int32 ItemsInUse = 0//元素个数
    
//指定存储空间的构造方法
    public SimpleDictionary(Int32 numItems)
    {
        items 
= new DictionaryEntry[numItems];
    }
    
#region IDictionary 成员
    
public bool IsReadOnly { get { return false; } }
    
public bool Contains(object key)
    {  
//检测是否包含指定的key键
       Int32 index;
       
return TryGetIndexOfKey(key, out index);
    }
    
public bool IsFixedSize { get { return false; } }
    
public void Remove(object key)
    {   
//移除指定键的元素
        Int32 index;
        
if (TryGetIndexOfKey(key, out index))
        {   
//把移除元素后面的所有元素向前移动一个位置
            Array.Copy(items, index + 1, items, index, ItemsInUse - index - 1);
            ItemsInUse
--;
        } 
    }
    
public void Clear() { ItemsInUse = 0; } //清除所有元素
    public void Add(object key, object value) 
    {   
//添加一个元素
        items[ItemsInUse++= new DictionaryEntry(key, value);
    }
    
public ICollection Keys
    {   
//返回所有键的集合
        get
        {   
//把所有键的集合拷贝到新数组中并返回
            Object[] keys = new Object[ItemsInUse];
            
for (Int32 n = 0; n < ItemsInUse; n++)
                keys[n] 
= items[n].Key;
            
return keys;
        }
    }
    
public ICollection Values
    {   
//返回所有值的集合
        get
        {   
//把所有值的集合拷贝到新数组中并返回
            Object[] values = new Object[ItemsInUse];
            
for (Int32 n = 0; n < ItemsInUse; n++)
                values[n] 
= items[n].Value;
            
return values;
        }
    }
    
public object this[object key]
    {   
//item属性的实现,也就是索引器
        get
        {   
            Int32 index;
            
if (TryGetIndexOfKey(key, out index))
            {
                
return items[index].Value;
            } 
            
return null;
        }
        
set
        {
            Int32 index;
            
if (TryGetIndexOfKey(key, out index))
            {
                items[index].Value 
= value;
            } 
            
else
            {
                Add(key, value);
            }
        }
    }
    
//这个方法有两个作用,第一是查找指定键是否存在
    
//第二是返回指定键的索引
    private Boolean TryGetIndexOfKey(Object key, out Int32 index)
    {
        
for (index = 0; index < ItemsInUse; index++)
        {
            
if (items[index].Key.Equals(key)) return true;
        }
        
return false;
    }
    
//用于迭代的嵌套类,它同时实现了IEnumerator和IDictionaryEnumerator
    private class SimpleDictionaryEnumerator : IDictionaryEnumerator
    {
        DictionaryEntry[] items;
        Int32 index 
= -1;
        
//构造方法,用于获得SimpleDictionary类的所有元素
        public SimpleDictionaryEnumerator(SimpleDictionary sd)
        {
            items 
= new DictionaryEntry[sd.Count];
            Array.Copy(sd.items, 
0, items, 0, sd.Count);
        }
        
public Object Current 
        { 
            
get { return items[index]; }
        }
        
public DictionaryEntry Entry
        {
            
get { return (DictionaryEntry) Current; }
        }
        
public Object Key { get { return items[index].Key; } }
        
public Object Value { get { return items[index].Value; } }
        
public Boolean MoveNext()
        {
            
if (index < items.Length - 1) { index++return true; }
            
return false;
        }
        
public void Reset()
        {
            index 
= -1;
        }
    }
    
//实现IDictionary接口中的GetEnumerator方法
    public IDictionaryEnumerator GetEnumerator()
    {
        
return new SimpleDictionaryEnumerator(this);
    }
    
#endregion

    
#region ICollection 成员
    
public bool IsSynchronized { get { return false; } }
    
//这句够简化,直接弹出异常不给使用
    public object SyncRoot { get { throw new NotImplementedException(); } }
    
public int Count { get { return ItemsInUse; } }
    
public void CopyTo(Array array, int index) { throw new NotImplementedException(); }
    
#endregion

    
#region IEnumerable 成员
    
//实现IEnumerable接口的GetEnumerator方法
    IEnumerator IEnumerable.GetEnumerator() 
    {
        
// 这里使用了强制类型转换.
        return ((IDictionary)this).GetEnumerator();
    }
    
#endregion
}
public sealed class App
{
    
static void Main()
    {
        
// 创建一个只能包含三个元素的字典类
        IDictionary d = new SimpleDictionary(3);
        
// 添加三个人名和它们的年龄到字典内
        d.Add("Jeff"40);
        d.Add(
"Kristin"34);
        d.Add(
"Aidan"1);
        Console.WriteLine(
"字典元素个数= {0}", d.Count);
        Console.WriteLine(
"字典中是否包含'Jeff'? {0}", d.Contains("Jeff"));
        Console.WriteLine(
"Jeff的年龄是:{0}", d["Jeff"]);
        
// 显示字典中的所有键和值,由于实现了IDictionaryEnumerator接口
        
//所以可以使用foreach进行调用
        foreach (DictionaryEntry de in d)
        {
            Console.WriteLine(
"{0} is {1} years old.", de.Key, de.Value);
        }
        
// 移除“Jeff”
        d.Remove("Jeff");
        
// 移除不存在的元素不会引发异常
        d.Remove("Max");
        
// 显示字典中的所有人名(key)
        foreach (String s in d.Keys)
            Console.WriteLine(s);
        
// 显示字典中的所有年龄(value)
        foreach (Int32 age in d.Values)
            Console.WriteLine(age);
    }
}

posted @ 2008-02-15 10:18  abatei  阅读(2166)  评论(0编辑  收藏  举报