在下面的代码中,为什么 y.e[0].k 不等于 20 而不是 30? 显然发生的是 y.e[0] = x.e[0]
但我需要的是在实例化 y 时将列表从 x 复制到 y,而不仅仅是将指针 x.e 复制到 y.e;
但是:x.c 为真,y.c 为假,如我所料。
感谢任何有用的评论
class Eclass {
public int k { get; set; }
public Eclass(int iK) { k = iK; }
}
class Sclass {
private static int ID = -1;
public long Id { get; set; }
public bool c { get; set; }
public List<Eclass> e { get; set; }
public Sclass() {
c = false;
Id = ++ID;
e = new List<Eclass>();
}
public Sclass(Sclass org) {
c = org.c;
Id = ++ID;
//foreach (var OrgE in org.e) { e.Add(OrgE); } //also doesn't work
//e = org.e.ToList();
e = new List<Eclass>(org.e);
}
}
class Program {
static void Main(string[] args)
{
Console.WriteLine("steve");
Eclass e1 = new Eclass(1);
Eclass e2 = new Eclass(2);
Eclass e3 = new Eclass(3);
Eclass e4 = new Eclass(4);
Sclass x = new Sclass();
x.c = false;
x.c = true;
x.e.Add(e1);
x.e.Add(e2);
Sclass y = new Sclass(x);
x.e.Add(e3);
y.e.Add(e4);
x.e[0].k = 10;
y.e[0].k = 20;
x.c = false;
Debug.WriteLine("//{0}// //{1}// :: //{2}// //{3}//", x.c, x.e[0].k, y.c, y.e[0].k);
x.c = !x.c;
y.c = !y.c;
x.e[0].k = 30;
Debug.WriteLine("//{0}// //{1}// :: //{2}// //{3}//", x.c, x.e[0].k, y.c, y.e[0].k);
}
}
//False// //20// :: //True// //20//
//True// //30// :: //False// //30//
最佳答案
您创建了 y
使用 Sclass
复制构造函数:
Sclass y = new Sclass(x);
问题是 Sclass
中的这一行复制构造函数。那就是y.e
来自:
e = org.e.ToList();
这会创建一个 org.e
的副本-- 一个新的 List<Eclass>
,它引用了旧项目中的原始项目。因此,x.e[0]
与 y.e[0]
是同一个对象.然后你给y.e
和 x.e
e2
之后每增加一项,但你从不看那些。
因为 Eclass
是引用类型而不是值类型,您需要显式复制每个 Eclass
列表中的实例,而不仅仅是列表本身的副本。如果你改变 Eclass
来自class
到 struct
,副本将自动生成,因为那样它就不是引用类型了。然后你应该看到你期望的语义。 Eclass
会表现得像 int k
: 赋值会创建值的新副本,而不是对旧对象的新引用。
不过,更常用的方法是给出 Eclass
一个克隆方法,它返回一个新的、相同的 Eclass
副本-- 或者给它一个复制构造函数,很像 Sclass
的复制构造函数.我比 Clone()
更喜欢复制构造函数因为 .NET 框架倾向于更多地使用它们,在这种情况下,您已经为 Sclass
准备好了一个。 .保持一致。
public Eclass {
public Eclass() {}
public Eclass(int k) {
this.k = k;
}
public Eclass(Eclass org) {
k = org.k;
}
}
然后在 Sclass 复制构造函数中,像这样复制 e:
public Sclass(Sclass org) {
c = org.c;
Id = ++ID;
// For each item in org.e, create an identical copy, and then make a list of those.
e = org.e.Select(ec => new Eclass(ec)).ToList();
}
这称为“深拷贝”:它制作“根”对象的副本,并用它引用的所有引用类型对象的副本填充它。
你现在做的是一个“浅拷贝”。
关于c# - 实例化时 List<T> 的副本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40407367/