程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> 構建可反轉排序的泛型字典類(4)--IDictionary接口

構建可反轉排序的泛型字典類(4)--IDictionary接口

編輯:關於C#

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);
  }
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved