C# 浅拷贝还是深拷贝?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18066429/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:12:25  来源:igfitidea点击:

Shallow copy or Deep copy?

c#deep-copyshallow-copy

提问by Srinivas Cheruku

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

采纳答案by Rohit Vats

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.

回答by Vaughan Hilts

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:

这是一个浅拷贝,因为如果您修改 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;
    }



    }

回答by Christopher Painter

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.

在将第一个对象分配给第二个对象后,再编写几行代码来更改第一个对象的属性。然后在两个对象上调用 display 方法,看看结果如何。这将向您揭示它实际上是一个浅拷贝。

回答by Will Yu

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.

ob2 = ob1; 这段代码创建了两个引用同一个对象的对象引用。因此,通过 ob1 对对象所做的任何更改都将反映在 ob2 的后续使用中。

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

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

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

回答by EKanadily

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 是值类型,所以当你写这行代码时:

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.

当这行代码被执行时,运行时会在 RAM 中找到一个位置并在其中写入值 5。因此,如果您搜索该位置,您会发现实际值为 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.

发生的情况是虚拟机(运行时): 1- 在内存中查找并找到可用位置,创建 MyClass 类的实例。假设该对象的位置恰好位于 RAM 中的字节#AA3D2。

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.

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

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.

现在,如果您查看“myObject”变量,您将找到的不是类实例,而是 AA3D2,它表示保存该类实例的内存位置。

now lets examine the code given my the OP:

现在让我们检查给定我的 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 类的实例并将该类的位置存储在 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 类中的变量 a。然后调用 display() 方法

A ob2 = new A();

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

这里它创建了一个名为 ob2 的变量,创建了类 A 的一个实例并将其位置分配给 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;

到现在为止,您在内存中有 2 个 A 类实例和 2 个变量,每个实例都指向其中一个。现在是有趣的部分: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 的值。因为 ob1 包含 A 的第一个实例的内存位置,现在 ob1 和 ob2 都指向内存中的相同位置。使用其中一个做任何事情都与另一个完全一样。

ob2 = ob1 means you are copying the reference.

ob2 = ob1 表示您正在复制引用。

回答by Anthony

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

我赞同@docesam 的回答和@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

ob2 = ob1; 这段代码创建了两个引用同一个对象的对象引用。因此,通过 ob1 对对象所做的任何更改都将反映在 ob2 的后续使用中。——于威尔



According to MSDN (see Remarks):

根据MSDN(见备注)

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.

Array 的浅拷贝仅复制 Array 的元素,无论它们是引用类型还是值类型,但不会复制引用所引用的对象。新 Array 中的引用指向与原始 Array 中的引用所指向的相同对象。

Here we have two things to note:

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

  1. A shallow copy copies elements.
  2. A shallow copy retains the original references of the elements.
  1. 浅拷贝复制元素。
  2. 浅拷贝保留元素的原始引用。

Next, let me explain these two separately.

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



To begin with, we create a Personclass with a Nameproperty:

首先,我们创建一个Person具有Name属性的类:

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

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

然后在Main()方法中,我们创建了一个Person数组。

// Create 2 Persons.
var person1 = new Person(){ Name = "Hyman" };
var person2 = new Person(){ Name = "Amy" };

// Create a Person array.
var arrPerson = new Person[] { person1, person2 };


1. A shallow copy copies elements.

1. 浅拷贝复制元素。

If we replacethe 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: Hyman, Amy
The Shallow Copy: Peter, Amy


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

2. 浅拷贝保留元素的原始引用。

If we changethe 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 = ob1is not a shallow copy but a reference copy.

总之ob2 = ob1不是浅拷贝,而是参考拷贝。

Full code to play with:

完整代码:

void Main()
{
    // Create 2 Persons.
    var person1 = new Person(){ Name = "Hyman" };
    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;}
}