ImmutableDictionary仍抛Collection was modified异常的原因与解决方法
问题根源
你把Dictionary换成ImmutableDictionary后仍然报错,核心原因是:ImmutableDictionary的不可变性只保护字典的键值对结构(不能增删改键值对),但它存储的Value是List<int>——这是个可变集合,其他线程依然可以修改这个List的内容。
当string.Join(",", status.Value)执行时,内部会创建List<int>的枚举器来遍历元素,如果此时其他线程对这个List做了Add/Remove/Clear等修改操作,就会触发"集合已被修改;枚举操作可能无法执行"的异常。
解决方案
给你三个可行的解决思路,按推荐优先级排序:
1. 将Value替换为不可变集合(最优)
把字典里的List<int>换成ImmutableList<int>,让Value本身也具备不可变性,彻底杜绝被修改的可能:
- 修改函数参数类型:
public string FormatLoDestStatus(ImmutableDictionary<string, ImmutableList<int>> loDestStatus) - 构建
loDestStatus字典时,把每个List<int>转换成ImmutableList<int>:// 示例:原List<int>转ImmutableList<int> var immutableList = originalList.ToImmutableList();
这样字典的键值对和内部的Value都不可变,多线程访问时不会出现枚举冲突。
2. 对可变List创建快照(快速修复)
如果暂时无法修改字典的Value类型,可以在枚举前先复制一份List的快照,基于快照进行操作:
foreach (var status in loDestStatus) { // 先复制一份快照,避免原List被修改影响枚举 var valueSnapshot = status.Value.ToList(); string value = string.Join(",", valueSnapshot).TrimEnd(); // 后续逻辑不变... }
这样即使其他线程修改了原List,快照是独立的副本,枚举时不会触发异常。
3. 加锁保护List的访问(最后选择)
如果既不能换不可变集合,又不想做快照,可以对所有访问该List
- 首先定义一个与List绑定的锁对象(注意:锁对象要和List一一对应,或者用字典级别的锁,根据实际情况选择)
- 在读取枚举List时加锁,修改List时也加同一个锁:
// 假设每个List有对应的锁,或者用全局锁(全局锁粒度大,性能差) lock (status.ValueLock) // 这里需要你提前为每个List创建对应的锁对象 { string value = string.Join(",", status.Value).TrimEnd(); }
这种方式要注意锁的粒度,避免出现死锁或性能瓶颈,必须保证所有读写操作都经过同一把锁。
内容的提问来源于stack exchange,提问作者user27330175
相关产品推荐
相关产品推荐

