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

構建可反轉排序的泛型字典 (6/9):實現 Keys/Values 屬性返回 IList<T> 視圖與自定義枚舉器

     編輯:關於C#

設計目標

標準 `IDictionary.Keys/Values` 返回 `ICollection`,功能有限(無索引存取)。本節實現返回 `IList` 的強類型視圖,支援:

  • 索引存取:`dict.Keys[3]`、`dict.Values[4]`
  • Contains、IndexOf、CopyTo
  • 唯讀語義(禁止 Add/Insert/Remove/Clear/SetItem)
  • 高效枚舉(直接引用內部陣列,無複製開銷)

自定義枚舉器:Key/Value 專用


// 鍵枚舉器
private sealed class KeyEnumerator : IEnumerator, IDisposable, IEnumerator
{
    private readonly ReversibleSortedList _dict;
    private int _index, _version;
    private TKey _current;

    internal KeyEnumerator(ReversibleSortedList dict)
    { _dict = dict; _version = dict._version; }

    public bool MoveNext()
    {
        if (_version != _dict._version) throw new InvalidOperationException("集合已修改");
        if (_index < _dict.Count)
        {
            _current = _dict._keys[_index++];
            return true;
        }
        _index = _dict.Count + 1;
        _current = default;
        return false;
    }

    public TKey Current => _current;
    object IEnumerator.Current => _current;
    void IEnumerator.Reset() { if (_version != _dict._version) throw new InvalidOperationException("集合已修改"); _index = 0; _current = default; }
    public void Dispose() { _index = 0; _current = default; }
}

// 值枚舉器(結構類似,略)

KeyList / ValueList:實現 IList<T> 唯讀視圖


private sealed class KeyList : IList, ICollection, IEnumerable, ICollection, IEnumerable
{
    private readonly ReversibleSortedList _dict;
    internal KeyList(ReversibleSortedList dict) => _dict = dict;

    // 唯讀操作拋出 NotSupportedException
    public void Add(TKey item) => throw new NotSupportedException();
    public void Clear() => throw new NotSupportedException();
    public void Insert(int index, TKey item) => throw new NotSupportedException();
    public bool Remove(TKey item) => throw new NotSupportedException();
    public void RemoveAt(int index) => throw new NotSupportedException();
    public TKey this[int index] { get => _dict.GetKey(index); set => throw new NotSupportedException(); }

    // 支援操作
    public bool Contains(TKey item) => _dict.ContainsKey(item);
    public int IndexOf(TKey item) => _dict.IndexOfKey(item);
    public void CopyTo(TKey[] array, int arrayIndex) => Array.Copy(_dict._keys, 0, array, arrayIndex, _dict.Count);
    public IEnumerator GetEnumerator() => new KeyEnumerator(_dict);
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

    public int Count => _dict.Count;
    public bool IsReadOnly => true;
    bool ICollection.IsSynchronized => false;
    object ICollection.SyncRoot => _dict;

    void ICollection.CopyTo(Array array, int index)
    {
        if (array?.Rank != 1) throw new ArgumentException("需一維陣列");
        try { Array.Copy(_dict._keys, 0, array, index, _dict.Count); }
        catch (ArrayTypeMismatchException) { throw new ArgumentException("陣列類型錯誤"); }
    }
}

// ValueList 結構類似,委託 _dict.GetByIndex(index) 等

外部類輔助方法與屬性


// 內部欄位
private KeyList _keyList;
private ValueList _valueList;

// 公有屬性
public IList Keys => GetKeyListHelper();
public IList Values => GetValueListHelper();

// 延遲初始化視圖
private KeyList GetKeyListHelper() => _keyList ??= new KeyList(this);
private ValueList GetValueListHelper() => _valueList ??= new ValueList(this);

// 供視圖調用的內部方法
internal TKey GetKey(int index)
{
    if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index));
    return _keys[index];
}
internal TValue GetByIndex(int index)
{
    if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index));
    return _values[index];
}
internal int IndexOfKey(TKey key) => Array.BinarySearch(_keys, 0, _size, key, _comparer);
internal int IndexOfValue(TValue value) => Array.IndexOf(_values, value, 0, _size);
internal bool ContainsKey(TKey key) => IndexOfKey(key) >= 0;
internal bool ContainsValue(TValue value) => IndexOfValue(value) >= 0;

測試驗證


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("Keys 索引存取: rs.Keys[3] = " + rs.Keys[3]); // 4
    Console.WriteLine("Values 索引存取: rs.Values[4] = " + rs.Values[4]); // e

    Console.WriteLine("\nKeys Contains/IndexOf:");
    Console.WriteLine($"Contains(2): {rs.Keys.Contains(2)}"); // true
    Console.WriteLine($"IndexOf(5): {rs.Keys.IndexOf(5)}"); // 4

    Console.WriteLine("\nValues CopyTo:");
    var arr = new string[rs.Count];
    rs.Values.CopyTo(arr, 0);
    Console.WriteLine(string.Join(", ", arr)); // b, c, a, f, e, d

    Console.WriteLine("\n嘗試修改 Keys[0] (應拋出異常):");
    try { rs.Keys[0] = 99; } catch (NotSupportedException) { Console.WriteLine("已攔截: 唯讀視圖"); }
}

設計亮點

  1. 零複製:視圖直接引用內部 `_keys`/`_values` 陣列,`CopyTo` 使用 `Array.Copy` 高效複製。
  2. 版本檢查:枚舉器攜帶 `_version` 快照,檢測並發修改。
  3. 介面隔離:`KeyList`/`ValueList` 實現完整 `IList`/`ICollection`/`IEnumerable` 及非泛型對應介面,無縫融入 .NET 生態。
  4. 唯讀保護:所有寫入操作統一拋出 `NotSupportedException`,語義清晰。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved