对于将一个对象复制到另一个对象的这两种方法,我有点新鲜。我很困惑,无法发现深拷贝和浅拷贝之间的主要区别。我已经经历了很多关于此的理论,但我需要用适当的例子进行解释。 我有一个程序,我将一个对象复制到另一个对象。 - >
class A
{
public int a = 0;
public void display()
{
Console.WriteLine("The value of a is " + a);
}
}
class Program
{
static void Main(string[] args)
{
A ob1 = new A();
ob1.a = 10;
ob1.display();
A ob2 = new A();
ob2 = ob1;
ob2.display();
Console.Read();
}
}
这是浅拷贝还是深拷贝?任何人都可以请原因提供答案。如果是深拷贝,那么请为该程序提供浅拷贝的代码,执行相同的对象复制工作,反之亦然。
如果以上是浅拷贝,那么即使这应该是浅拷贝 - >
A ob1 = new A();
ob1.a = 10;
ob1.display();
A ob2 = ob1;
ob2.a = 444;
ob1.display();
答案 0 :(得分:54)
从链接here
浅拷贝尽可能少复制。浅的副本 集合是集合结构的副本,而不是元素。 通过浅拷贝,两个集合现在共享个人 元件。
深拷贝复制一切。集合的深层副本是两个 包含原始集合中所有元素的集合 复制。
您的示例是创建一个浅表副本。
A ob1 = new A();
ob1.a = 10;
A ob2 = new A();
ob2 = ob1;
ob1.a = 5; // <-- If you see value of ob2.a after this line, it will be 5.
深拷贝将是 -
A ob1 = new A();
ob1.a = 10;
A ob2 = new A();
ob2.a = ob1.a;
ob1.a = 5; // <-- If you see value of ob2.a after this line, it will be 10.
答案 1 :(得分:15)
在我看来,它不是严格的浅拷贝或深拷贝。如果我必须定义它,我会说浅拷贝。
ob2 = ob1; 此代码创建两个引用同一对象的对象引用。因此,通过ob1对对象进行的任何更改都将反映在ob2的后续使用中。
来自MSDN的示例可以更好地解释浅拷贝,深拷贝和简单类拷贝的差异。
using System;
public class IdInfo
{
public int IdNumber;
public IdInfo(int IdNumber)
{
this.IdNumber = IdNumber;
}
}
public class Person
{
public int Age;
public string Name;
public IdInfo IdInfo;
public Person ShallowCopy()
{
return (Person)this.MemberwiseClone();
}
public Person DeepCopy()
{
Person other = (Person)this.MemberwiseClone();
other.IdInfo = new IdInfo(this.IdInfo.IdNumber);
other.Name = String.Copy(this.Name);
return other;
}
}
public class Example
{
public static void Main()
{
// Create an instance of Person and assign values to its fields.
Person p1 = new Person();
p1.Age = 42;
p1.Name = "Sam";
p1.IdInfo = new IdInfo(6565);
// Perform a shallow copy of p1 and assign it to p2.
Person p2 = (Person)p1.ShallowCopy();
// Display values of p1, p2
Console.WriteLine("Original values of p1 and p2:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p2 instance values:");
DisplayValues(p2);
// Change the value of p1 properties and display the values of p1 and p2.
p1.Age = 32;
p1.Name = "Frank";
p1.IdInfo.IdNumber = 7878;
Console.WriteLine("\nValues of p1 and p2 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p2 instance values:");
DisplayValues(p2);
// Make a deep copy of p1 and assign it to p3.
Person p3 = p1.DeepCopy();
// Change the members of the p1 class to new values to show the deep copy.
p1.Name = "George";
p1.Age = 39;
p1.IdInfo.IdNumber = 8641;
Console.WriteLine("\nValues of p1 and p3 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p3 instance values:");
DisplayValues(p3);
// Make an equal of p1 and assign it to p4.
Person p4 = new Person();
p4 = p1;
// Change the members of the p1 class to new values to show the equal copy.
p1.Name = "Will";
p1.Age = 30;
p1.IdInfo.IdNumber = 8484;
Console.WriteLine("\nValues of p1 and p4 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p4 instance values:");
DisplayValues(p4);
}
public static void DisplayValues(Person p)
{
Console.WriteLine(" Name: {0:s}, Age: {1:d}", p.Name, p.Age);
Console.WriteLine(" Value: {0:d}", p.IdInfo.IdNumber);
}
}
结果如下:
Original values of p1 and p2: p1 instance values:
Name: Sam, Age: 42
Value: 6565 p2 instance values:
Name: Sam, Age: 42
Value: 6565
Values of p1 and p2 after changes to p1: p1 instance values:
Name: Frank, Age: 32
Value: 7878 p2 instance values:
Name: Sam, Age: 42
Value: 7878
Values of p1 and p3 after changes to p1: p1 instance values:
Name: George, Age: 39
Value: 8641 p3 instance values:
Name: Frank, Age: 32
Value: 7878
Values of p1 and p4 after changes to p1: p1 instance values:
Name: Will, Age: 30
Value: 8484 p4 instance values:
Name: Will, Age: 30
Value: 8484
答案 2 :(得分:5)
这既不是浅层也不是深层副本,这是一个引用copy.let我解释:有两种类型的变量:值类型和引用类型。
值类型是计算机内存中的(命名)位置,用于保存变量的实际值。例如:int是一个值类型,所以当你编写这行代码时:
int MyInt = 5;
当执行这行代码时,运行时将在RAM中找到一个位置并在其中写入值5。因此,如果您搜索该位置,您会发现实际值为5。
引用类型-in contrast-是内存中的(命名)位置,它实际上不保存变量的值,但保存该值存在的内存位置。例如,假设您编写了以下代码:
MyClass myObject = new MyClass();
会发生什么是虚拟机(运行时): 1-查看并在内存中找到可用位置,创建MyClass类的实例。假设该对象的位置恰好位于RAM中的字节#AA3D2。
2-在内存中找到一个位置并创建一个MyClass类型的引用(引用是一个&#34;箭头&#34;它指向内存中的一个位置),命名为&#34; myObject&#34;并将值AA3D2存储在其中。
现在,如果你看看&#34; myObject&#34;变量你不会发现类实例,但你会发现AA3D2代表了保存该类实例的内存位置。
现在让我们检查OP给出的代码:
A ob1 = new A();
这将创建一个名为ob1的变量,创建A类的实例并将该类的位置存储在ob1中
ob1.a = 10;
ob1.display();
这将改变A类中的变量a。然后调用display()方法
A ob2 = new A();
这里创建一个名为ob2的变量,创建一个A类实例并将其位置分配给ob2。
到目前为止,你在内存中有2个A和2个变量的类实例,每个变量都指向其中一个。 现在这里是有趣的部分: ob2 = ob1;
为变量ob2赋值变量ob1的值。因为ob1包含A的第一个实例的内存位置,现在ob1和ob2都指向内存中的相同位置。使用其中一个做任何事情都与另一个完全相同。
ob2 = ob1表示您正在复制参考。
答案 3 :(得分:2)
这是一个浅层副本,因为如果修改ob2的变量 - 然后尝试打印ob1 - 它们将是相同的。这是因为C#中的类是类之间创建的链接。如果要进行深层复制,则应实现复制方法并手动复制字段。类似的东西:
class A
{
public int a = 0;
public void display()
{
Console.WriteLine("The value of a is " + a);
}
public A Copy()
{
A a = new A();
a.a = = this.a;
return a;
}
}
答案 4 :(得分:1)
我赞同@docesam的回答和@Will Yu的部分回答。
这既不是浅版也不是深版,这是参考副本。 - docesam
ob2 = ob1;此代码创建两个引用同一对象的对象引用。因此,通过ob1对对象进行的任何更改都将反映在ob2的后续使用中。 --Will Yu
Array的浅表副本仅复制Array的元素,无论它们是引用类型还是值类型,但它不会复制引用引用的对象。新数组中的引用指向与原始数组中的引用指向的相同对象。
这里有两点需要注意:
接下来,让我分别解释这两个。
首先,我们创建一个Person
类,其中包含Name
属性:
class Person
{
public string Name {get; set;}
}
然后在Main()
方法中,我们创建了一个Person
数组。
// Create 2 Persons.
var person1 = new Person(){ Name = "Jack" };
var person2 = new Person(){ Name = "Amy" };
// Create a Person array.
var arrPerson = new Person[] { person1, person2 };
<强> 1。浅拷贝复制元素。
如果我们替换浅层副本中的第一个元素,原始数组不应受到影响:
// Create a shallow copy.
var arrPersonClone = (Person[]) arrPerson.Clone();
// Replace an element in the shallow copy.
arrPersonClone[0] = new Person(){Name = "Peter"};
// Display the contents of all arrays.
Console.WriteLine( "After replacing the first element in the Shallow Copy" );
Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
Console.WriteLine( $"The Shallow Copy: {arrPersonClone[0].Name}, {arrPersonClone[1].Name}" );
结果:
The Original Array: Jack, Amy
The Shallow Copy: Peter, Amy
<强> 2。浅拷贝保留了元素的原始引用。
如果我们更改浅层副本中元素的属性,原始数组将受到影响,因为不会复制此元素引用的对象。
// Create a new shallow copy.
arrPersonClone = (Person[]) arrPerson.Clone();
// Change the name of the first person in the shallow copy.
arrPersonClone[0].Name = "Peter";
// Display the contents of all arrays.
Console.WriteLine( "After changing the Name property of the first element in the Shallow Copy" );
Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
Console.WriteLine( $"The Shallow Copy: {arrPersonClone[0].Name}, {arrPersonClone[1].Name}" );
结果:
The Original Array: Peter, Amy
The Shallow Copy: Peter, Amy
那么简单的等号=
如何表现?
它制作参考副本。对元素或引用对象的任何更改都将反映在原始数组和“复制”数组中。
// Create a reference copy.
var arrPersonR = arrPerson;
// Change the name of the first person.
arrPersonR[0].Name = "NameChanged";
// Replace the second person.
arrPersonR[1] = new Person(){ Name = "PersonChanged" };
// Display the contents of all arrays.
Console.WriteLine( "After changing the reference copy:" );
Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
Console.WriteLine( $"The Reference Copy: {arrPersonR[0].Name}, {arrPersonR[1].Name}" );
结果:
The Original Array: NameChanged, PersonChanged
The Reference Copy: NameChanged, PersonChanged
总之,ob2 = ob1
不是浅色副本,而是参考副本。
可以使用的完整代码:
void Main()
{
// Create 2 Persons.
var person1 = new Person(){ Name = "Jack" };
var person2 = new Person(){ Name = "Amy" };
// Create a Person array.
var arrPerson = new Person[] { person1, person2 };
// ----------- 1. A shallow copy copies elements. -----------
// Create a shallow copy.
var arrPersonClone = (Person[]) arrPerson.Clone();
// Replace an element in the shallow copy.
arrPersonClone[0] = new Person(){Name = "Peter"};
// Display the contents of all arrays.
Console.WriteLine( "After replacing the first element in the Shallow Copy:" );
Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
Console.WriteLine( $"The Shallow Copy: {arrPersonClone[0].Name}, {arrPersonClone[1].Name}" );
Console.WriteLine( "\n" );
// ----------- 2. A shallow copy retains the original references of the elements. -----------
// Create a new shallow copy.
arrPersonClone = (Person[]) arrPerson.Clone();
// Change the name of the first person in the shallow copy.
arrPersonClone[0].Name = "Peter";
// Display the contents of all arrays.
Console.WriteLine( "After changing the Name property of the first element in the Shallow Copy:" );
Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
Console.WriteLine( $"The Shallow Copy: {arrPersonClone[0].Name}, {arrPersonClone[1].Name}" );
Console.WriteLine( "\n" );
// ----------- 2. The equal sign. -----------
// Create a reference copy.
var arrPersonR = arrPerson;
// Change the name of the first person.
arrPersonR[0].Name = "NameChanged";
// Replace the second person.
arrPersonR[1] = new Person(){ Name = "PersonChanged" };
// Display the contents of all arrays.
Console.WriteLine( "After changing the reference copy:" );
Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
Console.WriteLine( $"The Reference Copy: {arrPersonR[0].Name}, {arrPersonR[1].Name}" );
}
class Person
{
public string Name {get; set;}
}
答案 5 :(得分:0)
在将第一个对象分配给第二个对象后,再写几行代码来更改第一个对象的属性。然后在两个对象上调用display方法并查看结果。这将向您揭示它实际上是一个浅层副本。