web-dev-qa-db-fra.com

Copie peu profonde ou copie profonde?

Je suis un peu nouveau à ces deux méthodes de copier un objet dans l’autre. Je suis confus et incapable de repérer la différence majeure entre la copie profonde et la copie superficielle .. J'avais beaucoup de théorie à ce sujet, mais j'ai besoin d'explications avec des exemples appropriés ... J'ai un programme dans lequel j'en copie une objet dans un autre. ->

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

Est-ce une copie superficielle ou une copie profonde? Quelqu'un peut-il s'il vous plaît fournir la réponse avec la raison. S'il s'agit d'une copie profonde, veuillez fournir le code de copie superficielle pour que ce programme effectue le même travail de copie d'objet, et inversement.

Si ce qui précède est une copie superficielle, cela devrait être même une copie superficielle ->

            A ob1 = new A();
            ob1.a = 10;
            ob1.display();
            A ob2 = ob1;
            ob2.a = 444;
            ob1.display();
32
Srinivas Cheruku

Du lien ici

Les copies superficielles dupliquent le moins possible. Une copie superficielle d'un collection est une copie de la structure de la collection, pas des éléments . Avec une copie superficielle, deux collections partagent maintenant l’individu éléments.

Les copies profondes dupliquent tout. Une copie complète d'une collection est deux collections avec tous les éléments de la collection originale dupliqué.

Votre exemple crée une copie superficielle.

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.

Copie profonde sera -

 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.
52
Rohit Vats

À mon avis, ce n'est pas une copie stricte superficielle ou profonde. Si je dois le définir, je dirais une copie superficielle.

ob2 = ob1; Ce code crée deux références d'objet qui font référence au même objet. Par conséquent, toute modification apportée à l'objet via ob1 sera reflétée dans les utilisations ultérieures d'ob2. 

Exemple de MSDN serait mieux expliquer les différences pour la copie superficielle, la copie profonde et simplement la copie de classe.

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

Voici les résultats:

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
14
Will Yu

Ce n’est ni une copie superficielle ni profonde, c’est une copie de référence. Expliquez-moi: il existe 2 types de variables: les types valeur et les types référence. 

un type de valeur est un emplacement (nommé) dans la mémoire de l'ordinateur qui contient la valeur réelle de la variable. Par exemple, int est un type de valeur. Ainsi, lorsque vous écrivez cette ligne de code:

int MyInt = 5;

lorsque cette ligne de code sera exécutée, le moteur d'exécution trouvera un emplacement dans la RAM et y inscrira la valeur 5. Par conséquent, si vous effectuez une recherche à cet endroit, vous obtiendrez une valeur réelle de 5.

un type de référence - à l'opposé - est un emplacement (nommé) en mémoire qui ne contient pas réellement la valeur de la variable mais conserve l'emplacement de la mémoire où cette valeur existe. à titre d'exemple, supposons que vous écriviez le code suivant: 

MyClass myObject = new MyClass();

ce qui se passe, c'est que la machine virtuelle (runtime): 1- cherche et trouve un emplacement disponible en mémoire, crée une instance de la classe MyClass. Disons que l'emplacement de cet objet se trouve être à l'octet # AA3D2 dans la RAM.

2- trouvez un emplacement en mémoire et créez une référence de type MyClass (une référence est une "flèche" qui pointe vers un emplacement en mémoire), nommez-le "myObject" et stockez-y la valeur AA3D2.

maintenant, si vous regardez la variable "myObject", vous ne trouverez pas l'instance de la classe mais vous trouverez AA3D2, qui représente l'emplacement de la mémoire contenant cette instance de la classe.

examinons maintenant le code donné à mon OP:

A ob1 = new A();

cela créera une variable appelée ob1, créera une instance de la classe A et stockera l'emplacement de cette classe dans ob1

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

cela changera la variable a qui est à l'intérieur de la classe A. il appelle ensuite la méthode display ()

A ob2 = new A();

ici, il crée une variable appelée ob2, crée une instance de la classe A et affecte son emplacement à ob2.

à présent, vous avez en mémoire 2 instances de classe de A et 2 variables pointant chacune vers l’une d’entre elles . Maintenant, voici la partie intéressante: ob2 = ob1;

la variable ob2 se voit attribuer la valeur de la variable ob1. parce que ob1 contient l'emplacement de la mémoire de la première instance de A, ob1 et ob2 désignent maintenant le même emplacement en mémoire. faire quoi que ce soit en utilisant l'un d'eux, c'est faire exactement la même chose que l'autre.

ob2 = ob1 signifie que vous copiez la référence.

5
EKanadily

C'est une copie superficielle, car si vous modifiez la variable ob2 - et essayez ensuite d'imprimer ob1 - elles seront identiques. Cela est dû au fait que les éléments en C # qui sont des classes créent des liens entre eux. Si vous souhaitez effectuer une copie en profondeur, vous devez implémenter une méthode de copie et copier les champs à la main. Quelque chose comme:

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



    }
2
Vaughan Hilts

J'approuve la réponse de @ docesam et une partie de la réponse de @ Will Yu. 

Ce n'est ni une copie superficielle ni profonde, c'est une copie de référence. - docesam


ob2 = ob1; Ce code crée deux références d'objet qui font référence au même objet. Par conséquent, toute modification apportée à l'objet via ob1 sera reflétée dans les utilisations ultérieures d'ob2. --Est-ce que Yu


Selon MSDN (voir Remarques) :

Une copie superficielle d'un tableau ne copie que les éléments du tableau, qu'il s'agisse de types de référence ou de types de valeur, mais ne copie pas les objets auxquels les références font référence. Les références dans le nouveau tableau pointent vers les mêmes objets que les références du tableau d'origine.

Ici nous avons deux choses à noter:

  1. Une copie superficielle copie des éléments.
  2. Une copie superficielle conserve les références d'origine des éléments.

Ensuite, laissez-moi vous expliquer ces deux séparément.


Pour commencer, nous créons une classe Person avec une propriété Name:

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

Ensuite, dans la méthode Main(), nous créons un tableau 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. Une copie superficielle copie les éléments.

Si nous replace le premier élément de la copie superficielle, le tableau d'origine ne devrait pas être affecté:

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

Résultats:

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

2. Une copie superficielle conserve les références d'origine des éléments.

Si nous changeons les propriétés d'un élément de la copie superficielle, le tableau d'origine sera affecté, car l'objet auquel cet élément fait référence n'est pas copié.

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

Résultats:

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

Alors, comment se comporte un simple signe égal, =?

Il fait une copie de référence. Toute modification des éléments ou des objets référencés sera reflétée à la fois dans le tableau d'origine et dans le tableau "copié".

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

Résultats:

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

En conclusion, ob2 = ob1 n'est pas une copie superficielle mais une copie de référence.

Code complet pour jouer avec:

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

Ecrivez quelques lignes de code supplémentaires pour modifier la propriété du premier objet après l'avoir affectée au deuxième objet. Appelez ensuite la méthode d'affichage sur les deux objets et voyez quels sont les résultats. Cela vous révélera qu'il s'agit en fait d'une copie superficielle.

0