2013-08-05 80 views
25

我对这两种将一个对象复制到另一个中的方法有点新。我很困惑,无法发现深拷贝和浅拷贝之间的主要区别..我已经通过了很多关于这个的理论,但我需要用适当的例子来解释.. 我有一个程序,我在其中复制一个对象到另一个。 - >浅拷贝或深拷贝?

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

这是一个浅拷贝:

的完整代码一起玩。 –

+0

关于对象复制的维基百科页面:http://en.wikipedia.org/wiki/Object_copy – Jerome

+8

@VaughanHilts - 我不会称之为“浅拷贝”,因为上面的代码根本不执行任何“obj1”的拷贝。 –

回答

43

从链接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. 

深副本将是 - 然后尝试和打印OB1 - -

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. 
+0

我找不到你。 '因为您没有将ob1赋值给ob2,而是您为变量a赋值。 –

+0

通过将ob2赋值给ob1,您指的是同一个实例,即ob1的字段中的任何更新都将反映在ob2字段中。 –

+0

更新我的回答与推理。 –

2

,因为如果你修改OB2的变量,它是一个浅拷贝,他们将是相同的。这是因为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; 
    } 



    } 
0

写的代码一对夫妇更行更改第一个对象的属性将其分配给第二个对象之后。然后调用两个对象的显示方法并查看结果是什么。这会告诉你,它实际上是一个浅拷贝。

9

在我看来,它不是一个严格的浅拷贝或深拷贝。如果我必须定义它,我会说浅拷贝。

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 
+0

最佳答案IMO –

+0

这应该标记为答案....干得好... – khaled4vokalz

+0

根本不需要String.Copy(this.Name)。在C#中(和Java一样),字符串是不可变的,所以原始和深度复制可以共享字符串。 –

4

这既不是浅还是深拷贝,这是参考副本。让我解释一下:有两种类型的变量:值类型和引用类型。

值类型是计算机内存中保存变量实际值的(指定)位置。例如:int是值类型,所以,当你写这行代码:

int MyInt = 5; 

当这行代码得到执行运行时会发现在RAM中的位置,并写在它的值5。因此,如果您搜索该位置,则会发现实际值为5.

引用类型-in contrast-是内存中的一个(命名)位置,它实际上并不保存变量的值,而是保存内存的位置那里存在价值。作为一个例子,假设你写了下面的代码:

MyClass myObject = new MyClass(); 

什么情况是,虚拟机(运行时): 1的外观和在内存中找到一个可用的位置,创建MyClass类的一个实例。可以说该对象的位置恰好在RAM中的字节#AA3D2处。

2-在内存中查找位置并创建MyClass类型的引用(引用是指向内存位置的“箭头”),将其命名为“myObject”并将值AA3D2存储在其中。

现在,如果您查看“myObject”变量,您将发现不是类实例,但会发现AA3D2,它表示存放该类实例的内存位置。

现在可以检查代码给我的OP:

A ob1 = new A(); 

这将创建一个名为OB1变量,创建一个类的实例,并存储在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表示您正在复制参考。

0

我赞同@docesam的回答和@Will Yu的部分答案。

这既不是浅也不是深拷贝,这是参考拷贝。 - docesam


OB2 = OB1;此代码创建两个引用同一个对象的对象引用。因此,通过ob1所做的对对象的任何更改都会反映在ob2的后续使用中。 --Will宇


根据MSDN (see Remarks)

阵列只复制数组的元素,无论是引用类型还是值类型的浅拷贝,但它不复制引用引用的对象。新数组中的引用指向与原始数组中的引用指向的相同对象。

在这里,我们有两点需要注意:

  1. 浅表副本复印件元素。
  2. 浅拷贝保留了元素的原始引用。

接下来,让我分别解释这两个。


首先,我们创建了一个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;} 
}