我构建了以下简单示例来说明我在实际代码中遇到的问题,这个问题要复杂得多。
首先,我的简单课程:
public class InnerTemp {
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
}
public class OuterTemp {
public List<InnerTemp> InnerTemps { get; set; }
}
实施:
var outerTemps = new List<OuterTemp>();
var innerTemps = new List<InnerTemp>();
innerTemps.Add(new InnerTemp() { A = 1, B = 2, C = 3 });
innerTemps.Add(new InnerTemp() { A = 4, B = 5, C = 6 });
for( int i = 1; i < 5; i++ ) {
foreach( InnerTemp innerTemp in innerTemps ) {
innerTemp.A += i;
innerTemp.B += i;
innerTemp.C += i;
}
var outerTemp = new OuterTemp()
{
InnerTemps = innerTemps
};
outerTemps.Add(outerTemp);
}
我在最后一行设置断点,即结束大括号。在第一次迭代中,outerTemps[0].InnerTemps[0].A
的值为2,如预期的那样。但是在第二个循环中,outerTemps[0].InnerTemps[0].A
的值变为4,这令我感到困惑。第一个对象的属性A仅仅因为添加了另一个对象而被踩踏。我完全希望outerTemps[1].InnerTemps[0].A
有所不同,但为什么我的原始财产会被踩到?
如何更改此设置,以便每次将新对象添加到集合时,以前的对象属性都不会被覆盖?
答案 0 :(得分:2)
正如我在评论中提到的那样,您正在创建innerTemps
列表的浅表副本,这会导致复制引用而不是创建列表中每个InnerTemp
对象的深层副本。
如果您希望在新创建的InnerTemp
中单独跟踪和修改单独的OuterTemp
个对象,则必须创建它们的深层副本。
根据建议here,我建议您在Copy
课程中创建InnerTemp
方法:
public class InnerTemp
{
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
public static InnerTemp Copy(InnerTemp source)
{
return new InnerTemp { A = source.A, B = source.B, C = source.C };
}
}
在为每个OuterTemp
创建新列表时使用它:
var outerTemp = new OuterTemp()
{
InnerTemps = innerTemps.Select(InnerTemp.Copy).ToList();
};
这将阻止循环计数器修改outerTemps
列表中的值。请注意,.ToList()
通过评估Select
枚举并返回新列表来隐式创建深层副本,因此您不必担心导致问题的列表引用。