如何将MyClassA的DictA键同步到MyClassB的ListB并实现变更同步?
解决方案
要实现DictA的键同步到ListB且实时更新,核心是让DictA的变更操作能被监听到。下面提供两种实用的实现方案:
方案1:基于可观察字典(ObservableDictionary)自动同步
原生Dictionary<string, object>没有内置的变更通知机制,我们可以实现一个支持INotifyCollectionChanged接口的ObservableDictionary,让字典的增删操作触发通知,再让MyClassB订阅该通知更新ListB。
代码实现
using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; // 实现支持变更通知的字典 public class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged { public event NotifyCollectionChangedEventHandler CollectionChanged; public event PropertyChangedEventHandler PropertyChanged; public new void Add(TKey key, TValue value) { base.Add(key, value); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new KeyValuePair<TKey, TValue>(key, value))); OnPropertyChanged(nameof(Keys)); } public new bool Remove(TKey key) { if (base.TryGetValue(key, out var value)) { var removedItem = new KeyValuePair<TKey, TValue>(key, value); var result = base.Remove(key); if (result) { OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removedItem)); OnPropertyChanged(nameof(Keys)); } return result; } return false; } public new void Clear() { var items = new List<KeyValuePair<TKey, TValue>>(this); base.Clear(); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); OnPropertyChanged(nameof(Keys)); } protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { CollectionChanged?.Invoke(this, e); } protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } // 定义MyClassA和MyClassB public class MyClassA { public ObservableDictionary<string, object> DictA { get; } = new ObservableDictionary<string, object>(); } public class MyClassB { public List<string> ListB { get; } = new List<string>(); public MyClassB(MyClassA myClassA) { // 初始化ListB为当前DictA的键 ListB.AddRange(myClassA.DictA.Keys); // 订阅字典变更事件,实时更新ListB myClassA.DictA.CollectionChanged += (sender, e) => { switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (var item in e.NewItems) { if (item is KeyValuePair<string, object> kvp) ListB.Add(kvp.Key); } break; case NotifyCollectionChangedAction.Remove: foreach (var item in e.OldItems) { if (item is KeyValuePair<string, object> kvp) ListB.Remove(kvp.Key); } break; case NotifyCollectionChangedAction.Reset: ListB.Clear(); break; } }; } }
使用示例
var a = new MyClassA(); var b = new MyClassB(a); // 添加键,ListB自动同步 a.DictA.Add("Key1", "Value1"); // 移除键,ListB自动同步 a.DictA.Remove("Key1"); // 清空字典,ListB自动清空 a.DictA.Clear();
方案2:自定义事件手动同步
如果不想引入自定义字典,可以在MyClassA中封装字典的修改方法,避免直接暴露DictA的修改权限,同时在修改时触发自定义事件,让MyClassB订阅事件更新ListB。
代码实现
public class MyClassA { private readonly Dictionary<string, object> _dictA = new Dictionary<string, object>(); // 对外只读暴露字典的键集合 public IReadOnlyCollection<string> DictKeys => _dictA.Keys; // 自定义变更事件 public event EventHandler<DictionaryChangedEventArgs> DictionaryChanged; // 封装添加操作 public void AddToDict(string key, object value) { _dictA.Add(key, value); OnDictionaryChanged(new DictionaryChangedEventArgs(DictionaryChangeType.Add, key)); } // 封装移除操作 public bool RemoveFromDict(string key) { if (_dictA.Remove(key)) { OnDictionaryChanged(new DictionaryChangedEventArgs(DictionaryChangeType.Remove, key)); return true; } return false; } // 封装清空操作 public void ClearDict() { _dictA.Clear(); OnDictionaryChanged(new DictionaryChangedEventArgs(DictionaryChangeType.Clear, null)); } protected virtual void OnDictionaryChanged(DictionaryChangedEventArgs e) { DictionaryChanged?.Invoke(this, e); } } // 自定义事件参数和操作类型 public enum DictionaryChangeType { Add, Remove, Clear } public class DictionaryChangedEventArgs : EventArgs { public DictionaryChangeType ChangeType { get; } public string Key { get; } public DictionaryChangedEventArgs(DictionaryChangeType changeType, string key) { ChangeType = changeType; Key = key; } } public class MyClassB { public List<string> ListB { get; } = new List<string>(); public MyClassB(MyClassA myClassA) { // 初始化ListB ListB.AddRange(myClassA.DictKeys); // 订阅变更事件更新ListB myClassA.DictionaryChanged += (sender, e) => { switch (e.ChangeType) { case DictionaryChangeType.Add: if (!string.IsNullOrEmpty(e.Key)) ListB.Add(e.Key); break; case DictionaryChangeType.Remove: if (!string.IsNullOrEmpty(e.Key)) ListB.Remove(e.Key); break; case DictionaryChangeType.Clear: ListB.Clear(); break; } }; } }
使用示例
var a = new MyClassA(); var b = new MyClassB(a); // 通过封装方法修改字典,ListB自动同步 a.AddToDict("Key2", 123); a.RemoveFromDict("Key2"); a.ClearDict();
注意事项
- 方案1的
ObservableDictionary可扩展更多操作(如替换值),根据需求补充即可; - 方案2必须确保所有字典修改都通过
MyClassA的封装方法进行,否则无法触发同步; - 多线程场景下,需给
ListB的更新操作加锁,避免并发修改异常。
内容的提问来源于stack exchange,提问作者YE1ET
相关产品推荐
相关产品推荐

