VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Objective-C编程 >
  • 构建反转排序的泛型字典类4—IDictionary接口

制作者:剑锋冷月 单位:无忧统计网,www.51stat.net
  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接口。所以我从MSDN上copy了一段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);
  }
}
 


相关教程