MemberwiseClone()和在C#中分配引用类型有什么区别?

时间:2016-11-08 13:27:08

标签: c# shallow-copy

如果我有这样的代码

val i = vec2t(1, 1) // Vec2t<Int> inferred from arguments type Int
println(i.size) // 8

val d = vec2t(1.0, 1.0) // the same but it's Vec2t<Double> this time
println(d.size) // 16

当我更改p2的值时,它也会改变p1的值,当我更改Object p3的值时,我得到相同的结果。我的问题是,如果两个逻辑都做同样的事情,那么分配和使用class Student { public string RollID { get; set; } } class Person { public Student student { get; set; } public string Address { get; set; } public string Name { get; set; } public Person Clone() { return (Person)this.MemberwiseClone(); } } class Client { static void Main() { Student s1 = new Student(); s1.RollID = "151"; Person p1 = new Person(); p1.Address = "bombay"; p1.Name = "foo"; p1.student = s1; Person p2 = p1.Clone(); p2.student.RollID = "1558"; Person p3 = p1; p3.student.RollID = "454"; } } 方法之间的真正区别是什么。如果我使用MemberwiseClone()方法,还有其他优势吗?

3 个答案:

答案 0 :(得分:4)

这里的问题是你做了很深的&#34;在浅拷贝上更新。如果你改变了p2.Address,它不会影响p1.Address;但如果更改p3.Address,它将更改影响p1.Address。

但是由于p1和p2共享对单个学生的引用,因此更改RollId会影响每个人。

Variable P1 ---->  <PERSON OBJECT 1>
                   |       .Address = 123 Elm St.
Variable P3 ---->  |
                   |       .Student  ----> <STUDENT OBJECT 1>
                   |_______________        |
                                           | .RollId // one value for all
Variable P2 ---->  <PERSON OBJECT 2>       |
                   |       .Address = ...  |
                   |       .Student  ----> |_________________
                   |_______________

答案 1 :(得分:2)

C#类由ref&#34;处理#34;默认情况下。这意味着当你将某个东西分配给另一个时,如果它是一个类而不是一个结构,你只需将指针指向新对象,而新对象就在内存中的两个句柄的同一位置。另一方面,您可以复制一个类。当你成员克隆某些东西时,你会创建一个新的对象,在内存中占据另一个位置。

现在这个Object.MemberwiseClone()方法是一个浅复制函数,只复制其中的类和结构,并且该类中的类将由ref保存。请参阅this

要深层复制某些类,您需要特别针对该类实现它,或者您可以找到使用反射写的通用类,这有点慢。

答案 2 :(得分:2)

MemberwiseClone方法通过创建新对象,然后将当前对象的非静态字段复制到新对象来创建浅表副本。如果字段是值类型,则执行字段的逐位复制。如果字段是引用类型,则复制引用但不引用引用的对象;因此,原始对象及其克隆引用相同的对象。

https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone(v=vs.85).aspx

有两种克隆:浅克隆和深克隆。

在浅层克隆中,副本中的任何引用值都指向与原始对象中相同的对象。 在深度克隆中,新对象的引用值设置为新对象。 要使深度克隆实现ICloneable接口,请返回一个New Person对象。