首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

構建可反轉排序的泛型字典 (7/9):實現非泛型 IDictionary 介面與 DictionaryEntry 枚舉支援

     編輯:關於C#

為什麼要實現非泛型 IDictionary?

雖然 .NET 2.0+ 推薦泛型介面,但為了**相容舊代碼**(.NET 1.x 遷移專案)、**支援 `foreach (DictionaryEntry de in dict)`** 語法,必須實現 `System.Collections.IDictionary`。此外,`IDictionary.GetEnumerator()` 返回 `IDictionaryEnumerator`,這是 `DictionaryEntry` 能在 foreach 中工作的關鍵。

類別宣告擴展


public class ReversibleSortedList : 
    IDictionary,                    // 新增
    IEnumerable>,
    ICollection,
    IEnumerable
{
    // ...
}

ICollection 顯式實現(共用 Count、Clear)


void ICollection.CopyTo(Array array, int index)
{
    if (array == null) throw new ArgumentNullException(nameof(array));
    if (array.Rank != 1) throw new ArgumentException("僅支援一維陣列");
    if (array.GetLowerBound(0) != 0) throw new ArgumentException("陣列下界必須為 0");
    if (index < 0 || index > array.Length) throw new ArgumentOutOfRangeException(nameof(index));
    if (array.Length - index < Count) throw new ArgumentException("目標陣列空間不足");

    // 嘗試轉為強類型陣列
    var kvArray = array as KeyValuePair[];
    if (kvArray != null)
    {
        for (int i = 0; i < Count; i++)
            kvArray[index + i] = new KeyValuePair(_keys[i], _values[i]);
    }
    else
    {
        var objArray = array as object[];
        if (objArray == null) throw new ArgumentException("陣列類型必須為 KeyValuePair[] 或 object[]");
        for (int i = 0; i < Count; i++)
            objArray[index + i] = new KeyValuePair(_keys[i], _values[i]);
    }
}

bool ICollection.IsSynchronized => false;
object ICollection.SyncRoot => this;

IDictionary 核心成員顯式實現


bool IDictionary.IsFixedSize => false;
bool IDictionary.IsReadOnly => false;

object IDictionary.this[object key]
{
    get
    {
        if (IsCompatibleKey(key))
        {
            int idx = IndexOfKey((TKey)key);
            return idx >= 0 ? _values[idx] : null;
        }
        return null;
    }
    set
    {
        VerifyKey(key);
        VerifyValueType(value);
        // 委託給泛型索引器(需先實現泛型介面)
        this[(TKey)key] = (TValue)value; 
    }
}

ICollection IDictionary.Keys => GetKeyListHelper();
ICollection IDictionary.Values => GetValueListHelper();

void IDictionary.Add(object key, object value)
{
    VerifyKey(key); VerifyValueType(value);
    Add((TKey)key, (TValue)value);
}

bool IDictionary.Contains(object key)
    => IsCompatibleKey(key) && ContainsKey((TKey)key);

IDictionaryEnumerator IDictionary.GetEnumerator()
    => new Enumerator(this); // 關鍵:返回實現 IDictionaryEnumerator 的結構體

void IDictionary.Remove(object key)
{
    if (IsCompatibleKey(key))
        Remove((TKey)key); // 委託給泛型 Remove
}

類型驗證輔助方法


private static void VerifyKey(object key)
{
    if (key == null) throw new ArgumentNullException(nameof(key));
    if (!(key is TKey)) throw new ArgumentException("鍵類型不匹配", nameof(key));
}

private static void VerifyValueType(object value)
{
    // 允許 null 的引用類型,或可空值類型
    if (value != null && !(value is TValue))
        throw new ArgumentException("值類型不匹配", nameof(value));
    if (value == null && typeof(TValue).IsValueType && Nullable.GetUnderlyingType(typeof(TValue)) == null)
        throw new ArgumentException("不可空值類型不能為 null", nameof(value));
}

private static bool IsCompatibleKey(object key)
{
    if (key == null) throw new ArgumentNullException(nameof(key));
    return key is TKey;
}

Enumerator 結構體雙介面實現回顧

在第 5 篇已定義:


private struct Enumerator : 
    IEnumerator>, 
    IDictionaryEnumerator, 
    IEnumerator, 
    IDisposable
{
    // 同時實現:
    // - IEnumerator>.Current -> KeyValuePair
    // - IDictionaryEnumerator.Entry/Key/Value -> DictionaryEntry 相容
    // - IEnumerator.Current -> DictionaryEntry (為了非泛型 foreach)
}

這使得同一枚舉器同時支援:

  • `foreach (KeyValuePair kv in dict)` — 泛型
  • `foreach (DictionaryEntry de in (IDictionary)dict)` — 非泛型

測試驗證


static void Main()
{
    var rs = new ReversibleSortedList();
    rs.Add(3, "a"); rs.Add(1, "b"); rs.Add(2, "c");
    rs.Add(6, "d"); rs.Add(5, "e"); rs.Add(4, "f");

    Console.WriteLine("非泛型 IDictionary 枚舉 (DictionaryEntry):");
    foreach (DictionaryEntry de in (IDictionary)rs)
        Console.WriteLine($"{de.Key} = {de.Value}");

    Console.WriteLine("\n泛型枚舉 (KeyValuePair):");
    foreach (var kv in rs)
        Console.WriteLine($"{kv.Key} = {kv.Value}");

    Console.WriteLine("\n非泛型索引器測試:");
    ((IDictionary)rs)[10] = "ten";
    Console.WriteLine($"rs[10] = {((IDictionary)rs)[10]}");
}

小結

非泛型 `IDictionary` 實現完成,關鍵點在於:

  1. 所有成員採用**顯式介面實現**,避免污染公開 API。
  2. 類型驗證方法 `VerifyKey`/`VerifyValueType` 確保運行時類型安全。
  3. 索引器、Add/Remove/Contains 內部委託泛型實現,避免代碼重複。
  4. 枚舉器雙介面實現,完美支援 `DictionaryEntry` 舊式遍歷。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved