2013-08-05 5 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. 

Deep копия будет -

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

Я не мог тебя достать. 'coz, вы не назначили ob1 для ob2, вместо этого вы сделали это для переменной a .. –

+0

. Назначив ob2 ob1, вы ссылаетесь на тот же экземпляр, то есть на любое обновление в поле ob1 будет отображаться в поле ob2. –

+0

Обновлен мой ответ с рассуждением. –

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; 
    } 



    } 
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

Это не является ни мелкой, ни глубокой копии, это отсылка копия.позвольте мне объяснить: существует 2 типа переменных: типы значений и ссылочные типы.

Тип значения - это (названное) местоположение в памяти компьютера, на котором хранится фактическое значение переменной. например: ИНТ является типом значения, поэтому, когда вы пишете эту строку кода:

int MyInt = 5; 

, когда эта строка кода выполняется получить среда выполнения будет найти место в памяти и записать значение 5 в нем. так что если вы будете искать это местоположение, вы найдете фактическое значение 5.

ссылочный тип - в отличие - это (названное) место в памяти, которое фактически не удерживает значение переменной, но удерживает местоположение памяти где это значение существует. в качестве примера предположим, что вы написали следующий код:

MyClass myObject = new MyClass(); 

, что происходит в том, что виртуальная машина (среда): 1- внешний вид и найти доступное местоположение в памяти, создать экземпляр класса MyClass. скажем, что местоположение этого объекта оказалось в байте # AA3D2 в ОЗУ.

2- найдите место в памяти и создайте ссылку типа MyClass (ссылка - «стрелка», указывающая на местоположение в памяти), назовите ее «myObject» и сохраните в ней значение AA3D2.

Теперь, если вы посмотрите на переменную «myObject», вы не найдете экземпляр класса, но вы найдете AA3D2, которые представляют местоположение памяти, в которой хранится этот экземпляр класса.

теперь позволяет исследовать код учитывая мой OP:

A ob1 = new A(); 

это сделает переменную ob1, создать экземпляр класса и сохранить местоположение этого класса в OB1

ob1.a = 10; 
ob1.display(); 

это изменит переменную a, которая находится внутри класса A. он затем вызвать метод отображения()

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


оЬ2 = OB1; Этот код создает две ссылки на объекты, которые относятся к одному и тому же объекту. Поэтому любые изменения объекта, созданного с помощью ob1, будут отражены в последующих применениях ob2. --будет Ю.


По 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;} 
} 
Смежные вопросы