SortedList 添加重复键会抛 ArgumentException;其内部用双数组+二分查找实现插入即排序,遍历天然有序;Keys/Values 为只读视图;适合需按键有序且支持索引访问的场景。

SortedList 添加元素时,键重复会怎样?
直接抛异常——Add(key, value) 不允许重复键。这是和 Dictionary 最关键的区别之一:Dictionary 允许用索引器赋值(dict[key] = value)来覆盖,而 Add 方法在键已存在时会立即 throw ArgumentException。
- 想安全更新?用索引器赋值:
sortedList[key] = newValue,它会插入新项或替换旧值 - 想先判断再加?用
ContainsKey(key)配合Add,但注意这不是原子操作,多线程下仍可能竞态 - 泛型版本要求
TKey实现IComparable(如int、string默认支持),否则运行时报错
为什么遍历时总是按键升序?内部是怎么维持排序的?
SortedList 不是靠每次遍历排序,而是「插入即排序」——它内部用两个平行数组(一个存键、一个存值),每次 Add 都用二分查找定位插入位置,然后挪动后续元素腾出空位。所以:
- 查找是
O(log n),比Dictionary的O(1)慢;但遍历是O(n)且天然有序,不用额外OrderBy - 索引访问(如
GetByIndex(2)或Keys[2])是真·数组下标,不是哈希映射——所以IndexOfKey("abc")返回的是排序后的位置,不是原始插入顺序 - 删掉中间一项(
RemoveAt(5))会导致后面所有索引前移,这点容易在循环中误用导致跳项或越界
Keys 和 Values 属性返回的是什么?能直接修改吗?
Keys 和 Values 返回的是只读视图(IReadOnlyCollection / IReadOnlyCollection),不是副本。它们反映当前排序状态,但本身不可写。
- 不能对
Keys调用Add或Clear——会报NotSupportedException - 遍历时可放心用
foreach (var k in sortedList.Keys),性能好且顺序确定 - 若需独立副本(比如要排序后再改),得显式转成列表:
new List(sortedList.Keys)
什么时候该选 SortedList,而不是 Dictionary 或 Listair>>?
核心看需求是否「既要按 key 快速查,又要按顺序遍历/取范围」。例如实现 LRU 缓存、时间序列配置表、带序号的配置项映射。
- 需要频繁
GetByIndex(i)或GetKey(i)取第 N 个元素?选SortedList;Dictionary不支持索引访问 - 数据量小(SortedList 省去手动排序开销
- 写入频繁(尤其随机插入)、又不关心遍历顺序?
Dictionary更快;SortedList插入平均O(n)(因数组搬移)
别忽略容量细节:TrimToSize() 能释放冗余内存,但调用后下次扩容又会重新分配——高频增删场景慎用。









