关于C#中Dictionary<TKey,TValue>的Collection<T>等效类型及自定义操作实现的疑问
嘿,这个问题问到点子上了!很多人在需要给字典的增删操作加自定义逻辑时,都会纠结:为啥List有Collection<T>这么方便的基类可以扩展,Dictionary就没有对应的现成工具呢?
首先得明确:C#官方确实没有提供和Collection<T>完全对应Dictionary<TKey,TValue>的基类,这也是你现在只能手动实现IDictionary<TKey, TValue>来包装内部字典的原因。
先说说Collection<T>存在的意义吧——它本质是给IList<T>做了一个“懒人友好”的包装基类:它已经帮你实现了IList<T>的大部分默认逻辑,你只需要重写InsertItem、RemoveItem这些受保护的方法,就能轻松注入自定义逻辑,根本不用自己从头实现整个接口的所有方法(比如Contains、IndexOf这些,都不用手写)。要是你自己手动实现IList<T>,那所有接口方法都得自己写,工作量大不说,还容易写错细节。
再回到你提到的KeyedCollection<TKey, TItem>:你说得太对了,它完全不能替代Dictionary<TKey, TValue>。它的设计是把线性列表和哈希表结合在一起,内部是按顺序存储元素的,所以移除操作得遍历整个列表找对应元素,时间复杂度是O(n),而Dictionary的移除是O(1),对于需要高效增删查的场景,KeyedCollection真的不适用。
你现在手动实现IDictionary<TKey, TValue>包装内部Dictionary的方式是完全可行的,不过我可以给你个小优化:不用硬着头皮实现整个接口的所有方法,把大部分方法直接委托给内部的_inner字典就行,只专注于你需要自定义逻辑的Add、Remove等方法。比如:
public class MyCustomDictionary<TKey, TValue> : IDictionary<TKey, TValue> { private readonly Dictionary<TKey, TValue> _inner = new(); // 自定义Add逻辑 public void Add(TKey key, TValue value) { // 这里写你的自定义前置逻辑,比如日志、校验 Console.WriteLine("准备添加键:" + key); _inner.Add(key, value); } // 自定义Remove逻辑 public bool Remove(TKey key) { // 这里写你的自定义前置逻辑 Console.WriteLine("准备移除键:" + key); return _inner.Remove(key); } // 下面这些方法直接委托给_inner,不用自己写逻辑 public TValue this[TKey key] { get => _inner[key]; set => _inner[key] = value; } public ICollection<TKey> Keys => _inner.Keys; public ICollection<TValue> Values => _inner.Values; public int Count => _inner.Count; public bool IsReadOnly => false; public void Add(KeyValuePair<TKey, TValue> item) => _inner.Add(item.Key, item.Value); public void Clear() => _inner.Clear(); public bool Contains(KeyValuePair<TKey, TValue> item) => _inner.Contains(item); public bool ContainsKey(TKey key) => _inner.ContainsKey(key); public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) => ((IDictionary<TKey, TValue>)_inner).CopyTo(array, arrayIndex); public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => _inner.GetEnumerator(); public bool TryGetValue(TKey key, out TValue value) => _inner.TryGetValue(key, out value); public void Remove(KeyValuePair<TKey, TValue> item) => ((IDictionary<TKey, TValue>)_inner).Remove(item); IEnumerator IEnumerable.GetEnumerator() => _inner.GetEnumerator(); }
这样你既保留了自定义逻辑的灵活性,又不用写一堆重复的模板代码。
目前来说,官方确实没有提供直接对应Collection<T>的字典扩展基类,所以你的包装方式是最合理的选择,而KeyedCollection因为设计目标不同,完全不适合替代Dictionary做高效的键值对操作。
内容来源于stack exchange

