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

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

編輯:關於C#

7. 實現IDictionary接口

前面做了很多努力,現在終於可以實現 IDictionary接口了。當然,之所以要先實現它,目的之一還是為了之前留下的 一點遺憾:在foreach中使用DictionaryEntry訪問集合中的元素。

需要 注意,由於ReversibleSortedList類最主要的接口是泛型IDictionary接口,實 現非泛型IDictionary接口主要是考慮到兼容性,試想,你的項目是用.NET 1.0 實現的,但現在你需要使用.NET 2.0繼續完善程序並使用到了一些.NET 2.0所獨 有的功能。但你並不想更改之前曾寫好並穩定運行了很久的程序,此時,兼容是 非常重要的。,IDictionary接口成員大部份是顯式接口成員實現。這一節請對 照第5節的圖2觀看,最好下載用圖片浏覽器打開,我們先改變 ReversibleSortedList類的聲明,加上IDictionary:

public class ReversibleSortedList<TKey, TValue> :

IDictionary, IEnumerable<KeyValuePair<TKey, TValue>>, ICollection, IEnumerable

從ICollection接口開始實現:

由於它的Count屬性 只是指示一個整數,可以和ICollection<KeyValuePain<TKey, TVlaue>>共用,並且前面已經實現了它,所以無需再另外實現。剩下的就 只是IsSynchnonised、SyncRoot屬性和CopyTo方法了,但CopyTo方法 ICollection<KeyValuePain<TKey, TVlaue>>接口中也有,在MSDN 中查看兩個方法的定義:

ICollection中的是:

void CopyTo(   Array array,  int index)

而 ICollection<KeyValuePain<TKey, TVlaue>>中的是

void CopyTo(T[] array, int arrayIndex)

可以看到array參數並不一樣,一 個是泛型,一個是數組,所以需要為這個方法實現兩個版本,當然,我們先實現 的是ICollection接口中的CopyTo方法:

void ICollection.CopyTo(Array array, int arrayIndex)
  {
     if (array == null)
    {
      throw new ArgumentNullException("array");
    }
     if (array.Rank != 1)
    {
      throw new ArgumentException(
        "不支持多維數組拷貝 ");
    }
    if (array.GetLowerBound(0) != 0)
    {  //檢查參數數組是否下限為
      throw new ArgumentException("A non-zero lower bound was provided");
    }
    if ((arrayIndex < 0) || (arrayIndex > array.Length))
    {  //檢查參數數組容量
       throw new ArgumentOutOfRangeException(
         "arrayIndex", "Need non negative number");
     }
    if ((array.Length - arrayIndex) < this.Count)
    {  //檢查參數數組容量
      throw new ArgumentException("Array plus the offset is too small");
    }
    //把參數array強制轉換為KeyValuePair<TKey, TValue>數組類型
    KeyValuePair<TKey, TValue>[] pairArray1 =
       array as KeyValuePair<TKey, TValue>[];
    if (pairArray1 != null)
    {  // 如果轉換成功,則拷貝數據
      for (int num1 = 0; num1 < this.Count; num1++)
      {
         pairArray1[num1 + arrayIndex] =
          new KeyValuePair<TKey, TValue>(this.keys[num1],
           this.values[num1]);
      }
    }
     else
    {  //如果轉換不成功,則把參數array強制轉化為 object數組
      object[] objArray1 = array as object[];
      if (objArray1 == null)
      {
         throw new ArgumentException("錯誤的數組類型");
      }
      try
      {
         for (int num2 = 0; num2 < this.Count; num2++)
         {
          objArray1[num2 + arrayIndex] =
              new KeyValuePair<TKey, TValue> (this.keys[num2],
                                 this.values[num2]);
        }
       }
      catch (ArrayTypeMismatchException)
       {
        throw new ArgumentException("錯 誤的數組類型");
      }
    }
  }

下面實現了ICollection接口的兩個私有屬性:

bool ICollection.IsSynchronized
  {
     get
    {
      return false;
    }
  }
  object ICollection.SyncRoot
  {
     get
    {
      return this;
    }
  }

好,現在開始正式實現IDictionary接口。首先是屬性:

  bool IDictionary.IsFixedSize
  {
     get
    {
      return false;
    }
  }
  bool IDictionary.IsReadOnly
  {
     get
    {
      return false;
    }
  }
  //item屬性,本質上就是索引器
  object IDictionary.this[object key]
  {
    get
     {
      if (ReversibleSortedList<TKey, TValue>.IsCompatibleKey(key))
      {
         int num1 = this.IndexOfKey((TKey)key);
        if (num1 >= 0)
        {
          return this.values[num1];
        }
      }
       return null;
    }
    set
    {
      ReversibleSortedList<TKey, TValue>.VerifyKey (key);
      ReversibleSortedList<TKey, TValue>.VerifyValueType(value);
      //這裡調用了 IDictionary<TKey, TValue>接口的Item屬性,由於
       //還沒有實現它,所以先把這句屏敝掉
      //this[(TKey) key] = (TValue)value;
    }
  }
  ICollection IDictionary.Keys
  {
    get
    {
       return this.GetKeyListHelper();
    }
  }
  ICollection IDictionary.Values
  {
    get
    {
      return this.GetValueListHelper();
     }
  }

首先注意,全部使用了顯式接口成員實現,也 就是說,只能通過接口調用這些方法。另外它的Item屬性調用了還未實現的 IDictionary<TKey, TValue>接口的Item屬性:

this[(TKey)key] = (TValue)value;

所以需要先把這句屏蔽掉,等最後再釋放出來。另外 調用了兩個新的私有方法,也需要加進去:

private static void VerifyKey(object key)
  {  //檢查key類型是否兼容TKey
     if (key.Equals(null))
    {
      throw new ArgumentNullException("key");
    }
    if (!(key is TKey))
    {  //檢查key是否和TKey兼容。注意,此時 TKey已經被替換為實際類型
      throw new ArgumentException (
        "參數類型錯誤", "key");
    }
  }
  private static void VerifyValueType (object value)
  {  //檢查value類型
    if (!(value is TValue) && ((value != null) || typeof (TValue).IsValueType))
    {
      throw new ArgumentException(
        "參數類型錯誤", "value");
    }
  }

VerifyValueType方法進行類型檢查時有一個奇怪的判斷,這一 點主要是針對C#2.0的可空類型而設的。也就是說,在這裡,空的值類型是合法 的。關於可空類型,可以參考:

http://cgbluesky.blog.163.com/blog/static/241235582008111129264 23/

下面,就剩下IDictionary接口成員方法沒有實現了。其中,由於 Clear()方法同時為IDictionary和ICollection <KeyValuePair<TKey, TValue>>的成員方法,但兩者的返回值和參數完全相同,所以可以共用一 個拷貝:

public void Clear()
  {
     this.version++;
    Array.Clear(this.keys, 0, this._size);
    Array.Clear(this.values, 0, this._size);
     this._size = 0;
  }

剩下的全部為顯式接口成員實現:

void IDictionary.Add(object key, object value)
  {   //做類型檢查再添加
    ReversibleSortedList<TKey, TValue>.VerifyKey(key);
    ReversibleSortedList<TKey, TValue>.VerifyValueType(value);
    this.Add((TKey)key, (TValue)value);
  }
  bool IDictionary.Contains(object key)
  {
    if (ReversibleSortedList<TKey, TValue>.IsCompatibleKey(key))
    {
       return this.ContainsKey((TKey)key);
    }
    return false;
  }
  IDictionaryEnumerator IDictionary.GetEnumerator()
  {
    return new ReversibleSortedList<TKey, TValue>.Enumerator<TKey, TValue>(
        this);
  }
  void IDictionary.Remove(object key)
  {
    if (ReversibleSortedList<TKey, TValue>.IsCompatibleKey(key))
    { //這裡調用了IDictionary<TKey, TValue>接口的Remove方法 ,由於
      //還沒有實現它,所以先把這句屏敝掉
       // this.Remove((TKey)key);
    }
  }

上面代碼調用了IsCompatibleKey(key)方法,需要把它加上去:

private static bool IsCompatibleKey(object key)
   {  //用於檢查鍵的類型並返回一個bool值
    if (key.Equals (null))
    { 
      throw new ArgumentNullException("key");
    }
     return (key is TKey);
  }

其中, IDictionaryEnumerator IDictionary.GetEnumerator()方法是我們期待已久的 ,實現了它就可以在foreach中使用DictionaryEntry訪問集合中的元素。另外 Remove方法調用了IDictionary<TKey, TValue>接口的Remove方法。當然 ,我們還未實現它,這是第二次這樣了,看樣子還是首先應該實現泛型接口再實 現非泛型接口。教訓慘痛啊!寫了這麼多,懶得改了,大家知道就行了。

好!終於完成了,現在終於可以看看成果了。改變Main方法如下:

  static void Main()
  {
     ReversibleSortedList<int, string> rs = new ReversibleSortedList<int, string>();
    //添加元素
    rs.Add(3, "a");
    rs.Add(1, "b");
    rs.Add(2, "c");
     rs.Add(6, "d");
    rs.Add(5, "e");
    rs.Add(4, "f");
    //使用DictionaryEntry打 印鍵/值
    foreach (DictionaryEntry d in (IDictionary)rs)
    {
      Console.WriteLine(d.Key + "   " + d.Value);
    }
}

ReversibleSortedList 0.6版本:實現IDictionary接口

運行結果:

1  b
2  c
3  a
4  f
5  e
6  d

很遺憾,由於IDictionary.GetEnumerator()是顯 式接口成員實現,只能使用接口調用。接下來,終於可以實現最重要的一個接口 IDictionary<TKey, TValue>了。

本文配套源碼

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