2013-08-05 83 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;} 
}