修改SortedDictionary自定义键属性后未重排?如何解决?
问题:SortedDictionary键修改后无法自动重新排序的解决办法
SortedDictionary设计为始终按键排序,但当自定义键对象的属性被修改后,字典不会自动感知键的变化并更新排序,导致遍历结果不符合预期。
示例代码
public class ContentKey { public int key_num = 0; } public static void Main(string[] args) { ContentKey a = new ContentKey() {key_num = 10}; ContentKey b = new ContentKey() {key_num = 20}; ContentKey c = new ContentKey() {key_num = 30}; SortedDictionary<ContentKey, string> dict = new SortedDictionary<ContentKey, string>(new KeyComparer()); dict.Add(a, "A"); dict.Add(c, "C"); dict.Add(b, "B"); foreach(var key_value in dict) { Console.WriteLine("Key val: " + key_value.Key.key_num + " Str: " + key_value.Value); } a.key_num = 50; foreach(var key_value in dict) { Console.WriteLine("Key val: " + key_value.Key.key_num + " Str: " + key_value.Value); } } public class KeyComparer : IComparer<ContentKey> { public int Compare(ContentKey a, ContentKey b) { return a.key_num.CompareTo(b.key_num); } }
现象与需求
第一次遍历输出顺序为A(10)、B(20)、C(30),符合预期;但修改a的key_num为50后,第二次遍历仍保持原顺序,而非预期的B(20)、C(30)、A(50)。要求无需删除重新插入键(实际场景中无法追踪哪些键被修改)的前提下解决该问题。
解决方案1:将键设计为不可变类型(推荐)
从根源上避免键值变化的问题,把ContentKey设为不可变类型,让排序依据的属性只能在构造时赋值,后续无法修改。
修改后的ContentKey:
public class ContentKey { public int KeyNum { get; } // 只读属性,仅构造时可赋值 public ContentKey(int keyNum) { KeyNum = keyNum; } }
使用方式:
ContentKey a = new ContentKey(10); ContentKey b = new ContentKey(20); ContentKey c = new ContentKey(30);
解决方案2:自定义可自动更新排序的字典包装类
通过监听键的属性变化事件,自动触发字典的排序更新。
步骤1:让键实现属性变更通知
public class ContentKey : INotifyPropertyChanged { private int _keyNum; public int KeyNum { get => _keyNum; set { if (_keyNum != value) { _keyNum = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(KeyNum))); } } } public event PropertyChangedEventHandler PropertyChanged; }
步骤2:实现自动排序的字典包装类
public class AutoSortedDictionary<TKey, TValue> where TKey : INotifyPropertyChanged { private readonly SortedDictionary<TKey, TValue> _innerDict; private readonly IComparer<TKey> _comparer; public AutoSortedDictionary(IComparer<TKey> comparer) { _comparer = comparer; _innerDict = new SortedDictionary<TKey, TValue>(comparer); } public void Add(TKey key, TValue value) { key.PropertyChanged += Key_PropertyChanged; _innerDict.Add(key, value); } private void Key_PropertyChanged(object sender, PropertyChangedEventArgs e) { var key = (TKey)sender; if (_innerDict.TryGetValue(key, out var value)) { // 移除并重新添加键,触发排序更新 _innerDict.Remove(key); _innerDict.Add(key, value); } } // 暴露遍历接口 public IEnumerable<KeyValuePair<TKey, TValue>> GetEnumerator() { return _innerDict; } // 按需实现其他字典方法,如ContainsKey、Remove、TryGetValue等 }
步骤3:使用自定义字典
var dict = new AutoSortedDictionary<ContentKey, string>(new KeyComparer()); dict.Add(a, "A"); dict.Add(c, "C"); dict.Add(b, "B");
修改a.KeyNum = 50后,字典会自动更新排序,遍历结果将符合预期。
解决方案3:手动触发全局重新排序
如果无法修改键类型,可在需要更新排序时,将所有键值对取出后重新构建字典:
// 在键属性修改后执行 var tempList = dict.ToList(); dict.Clear(); foreach (var kvp in tempList) { dict.Add(kvp.Key, kvp.Value); }
这种方法适合批量修改后统一更新排序的场景,但数据量较大时会有性能开销,需根据实际情况使用。
内容的提问来源于stack exchange,提问作者DragonGamer
相关产品推荐
相关产品推荐

