سؤال

I am a bit new to these two methods of copying one object into the other. I am confused and unable to spot out the major difference between deep copy and shallow copy.. I had gone through a lots of theory regarding this, but I need explanation with proper examples.. I have program in which I copy one object into another. -->

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

Is this a shallow copy or a deep copy ? Can anyone please provide the answer with reason. If it is a deep copy, then please provide the code for shallow copy for this program doing the same job of object copying, and the other way around..

If the above is a shallow copy, then even this should be a shallow copy-->

            A ob1 = new A();
            ob1.a = 10;
            ob1.display();
            A ob2 = ob1;
            ob2.a = 444;
            ob1.display();
هل كانت مفيدة؟

المحلول

From the link here

Shallow copies duplicate as little as possible. A shallow copy of a collection is a copy of the collection structure, not the elements. With a shallow copy, two collections now share the individual elements.

Deep copies duplicate everything. A deep copy of a collection is two collections with all of the elements in the original collection duplicated.

Your example is creating a shallow copy.

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 copy will be -

 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.

نصائح أخرى

In my opinion, it is not a strict shallow copy or deep copy. If I have to define it, I would say shallow copy.

ob2 = ob1; This code creates two object references that both refer to the same object. Therefore, any changes to the object made through ob1 will be reflected in subsequent uses of ob2.

Example from MSDN would be better to explain the differences for shallow copy, deep copy and just simply class copy.

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

Here are the results:

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

This is neither a shallow nor a deep copy, this is a reference copy.let me explain: there are 2 types of variables : value types and reference types.

a value type is a (named) location in computer memory that hold the actual value of the variable. for example: int is a value type, so when you write this line of code:

int MyInt = 5;

when this line of code get executed the runtime will find a location in the RAM and write the value 5 in it. so if you search that location you will find an actual value of 5.

a reference type -in contrast- is a (named) location in memory that does not actually hold the value of the variable but hold the location of memory where that value exists. as an example suppose you wrote the following code:

MyClass myObject = new MyClass();

what happens is that the virtual machine (runtime): 1- look and find an available location in memory , create an instance of the MyClass class. lets say that the location of that object happened to be at byte # AA3D2 in RAM.

2- find a location in memory and create a reference of type MyClass (a reference is an "arrow" that point to a location in memory),name it "myObject" and store the value AA3D2 in it.

now if you look at the "myObject" variable you will find not the class instance but you will find AA3D2 which represent the location of memory that hold that class instance.

now lets examine the code given my the OP:

A ob1 = new A();

this will make a variable called ob1 ,create instance of the A class and store the location of that class in ob1

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

this will change the variable a which is inside the A class. it then invoke the display() method

A ob2 = new A();

here it create a variable called ob2 ,create an instance of the class A and assign its location to ob2.

by now you have in memory 2 class instances of A and 2 variables each pointing to one of them. now here is the interesting part : ob2 = ob1;

the variable ob2 is assigned the value of the variable ob1. because ob1 contain the memory location of the first instance of A ,now both ob1 and ob2 point to the same location in memory. doing anything using one of them is exactly doing the same thin with the other.

ob2 = ob1 means you are copying the reference.

It's a shallow copy because if you modify the variable of ob2 - and then try and print ob1 - they will be the same. This is because things in C# that are classes create links between themselves. If you want to do a deep copy, you should implement a copy method and copy the fields by hand. Something like:

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



    }

I endorse the answer from @docesam and part of the answer from @Will Yu.

This is neither a shallow nor a deep copy, this is a reference copy. -- docesam


ob2 = ob1; This code creates two object references that both refer to the same object. Therefore, any changes to the object made through ob1 will be reflected in subsequent uses of ob2. --Will Yu


According to MSDN (see Remarks):

A shallow copy of an Array copies only the elements of the Array, whether they are reference types or value types, but it does not copy the objects that the references refer to. The references in the new Array point to the same objects that the references in the original Array point to.

Here we have two things to note:

  1. A shallow copy copies elements.
  2. A shallow copy retains the original references of the elements.

Next, let me explain these two separately.


To begin with, we create a Person class with a Name property:

class Person
{
    public string Name {get; set;}
}

Then in the Main() method, we create a Person array.

// 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.

If we replace the first element in the shallow copy, the original array should not be affected:

// 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}" );

Results:

The Original Array: Jack, Amy
The Shallow Copy: Peter, Amy

2. A shallow copy retains the original references of the elements.

If we change the properties of an element in the shallow copy, the original array will be affected, since the object which this element makes reference to is not copied.

// 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}" );

Results:

The Original Array: Peter, Amy
The Shallow Copy: Peter, Amy

So how does a simple equal sign, =, behave?

It makes a reference copy. Any change to the elements or the referred objects will be reflected in both the original array and the "copied" array.

// 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}" );

Results:

The Original Array: NameChanged, PersonChanged
The Reference Copy: NameChanged, PersonChanged

In conclusion, ob2 = ob1 is not a shallow copy but a reference copy.

Full code to play with:

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

Write a couple more lines of code to change the property of the first object after you assign it to the second object. Then call the display method on both objects and see what the results are. This will reveal to you that it is in fact a shallow copy.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top