关于实例化的List的副本
本文关键字:副本 List 实例化 | 更新日期: 2023-09-27 18:16:15
在下面的代码中,为什么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);
}
}
//假////20//:://真////20//
//True////30//:://False////30//
您使用Sclass
复制构造函数创建了y
:
Sclass y = new Sclass(x);
问题是Sclass
复制构造函数中的这一行。这就是y.e
的来源:
e = org.e.ToList();
这将创建一个org.e
的副本 - 一个新的List<Eclass>
,它引用了旧项目中的原始项目。因此,x.e[0]
与 y.e[0]
是同一对象。然后你给y.e
,并在e2
后x.e
每个额外的项目,但你从不看那些。
由于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();
}
这称为"深层复制":它创建"根"对象的副本,并用它引用的所有引用类型对象的副本填充它。
你现在做的是一个"浅拷贝"。
阅读评论。 您将看到信用属于@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);
}
}