在下面的代码中,为什么 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 //
答案 0 :(得分:4)
您使用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();
}
这被称为&#34;深拷贝&#34;:它制作了&#34; root&#34;的副本。 object,并使用它引用的所有引用类型对象的副本填充它。
你现在正在做的是一个&#34;浅拷贝&#34;。
答案 1 :(得分:-1)
阅读评论。您将看到该信用证属于@EdPlunkett
class Eclass {
public int k { get; set; }
public Eclass(int iK) { k = iK; }
public Eclass(Eclass org) { k = org.k; }
}
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;
e = org.e.Select(ec => new Eclass(ec)).ToList();
}
}
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);
}
}