雖然 .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
{
// ...
}
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;
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;
}
在第 5 篇已定義:
private struct Enumerator :
IEnumerator>,
IDictionaryEnumerator,
IEnumerator,
IDisposable
{
// 同時實現:
// - IEnumerator>.Current -> KeyValuePair
// - IDictionaryEnumerator.Entry/Key/Value -> DictionaryEntry 相容
// - IEnumerator.Current -> DictionaryEntry (為了非泛型 foreach)
}
這使得同一枚舉器同時支援:
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` 實現完成,關鍵點在於: