基于现有Dictionary创建新字典得到非预期结果问题咨询
问题根源
这个问题和ByVal/ByRef的差异无关,是引用类型传递的特性导致的:
- .NET中
List(Of T)属于引用类型,代码中传递的不是列表的副本,而是指向堆中实际列表对象的内存引用。 - 你的
appendToDict方法中,当新字典不存在对应key时,直接把原始字典里的List引用作为值添加到了新字典中,后续对新字典中这个List的修改,实际就是修改原始字典里的List对象。
异常执行流程梳理
- 第一次循环处理
2018对应的列表[User1,User2,User3]:- 调用
appendToDict("Users", 2018年列表, newDictionary),此时新字典没有Users键,直接把2018年的原始列表引用赋值给newDictionary("Users") - 接着调用
appendToDict("Alpha", 2018年列表, newDictionary),同样直接把2018年原始列表引用赋值给newDictionary("Alpha")
- 调用
- 后续处理2019、2020年的列表时:
- 调用
appendToDict("Users", 对应年份列表, newDictionary)时,Users键已经存在,会把后续年份的用户全部AddRange到newDictionary("Users")对应的列表里 - 但因为
newDictionary("Users")实际指向的就是2018年的原始列表,所以这一步相当于直接修改了原始字典里2018年对应的列表内容,同时newDictionary("Alpha")也指向同一个列表,所以Alpha列表也跟着变成了全部7个用户,原始字典也被意外修改。
- 调用
修复方案
修改appendToDict方法,当key不存在时,添加的是原始列表的副本而不是原始引用:
Private Sub appendToDict(key As String, val As List(Of String), dict As Dictionary(Of String, List(Of String))) If dict.ContainsKey(key) Then dict(key).AddRange(val) Else ' 这里创建新列表拷贝原始数据,不再共用引用 dict.Add(key, New List(Of String)(val)) End If End Sub
修改后所有新字典里的列表都是独立的对象,不会再互相影响,也不会修改原始字典的数据。
内容的提问来源于stack exchange,提问作者clarkcone
相关产品推荐
相关产品推荐

