浅拷贝还是深拷贝?

Sri*_*uku 33 c# deep-copy shallow-copy

我对将这一个对象复制到另一个对象的这两种方法有点新鲜.我很困惑,无法发现深拷贝和浅拷贝之间的主要区别..我已经经历了很多关于这个的理论,但我需要用适当的例子解释..我有一个程序,我将一个对象复制到另一个. - >

   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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

这是浅拷贝还是深拷贝?任何人都可以请原因提供答案.如果是深拷贝,那么请为此程序提供浅拷贝的代码,执行相同的对象复制工作,反之亦然.

如果以上是浅拷贝,那么即使这应该是浅拷贝 - >

            A ob1 = new A();
            ob1.a = 10;
            ob1.display();
            A ob2 = ob1;
            ob2.a = 444;
            ob1.display();
Run Code Online (Sandbox Code Playgroud)

Roh*_*ats 54

从这里的链接

浅拷贝尽可能少复制.集合的浅表副本是集合结构的副本,而不是元素.使用浅拷贝,两个集合现在共享各个元素.

深拷贝复制一切.集合的深层副本是两个集合,原始集合中的所有元素都是重复的.

您的示例是创建浅表副本.

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.
Run Code Online (Sandbox Code Playgroud)

深拷贝将 -

 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.
Run Code Online (Sandbox Code Playgroud)

  • 但是,ob1和ob2有自己的内存分配是不同的,因为我具体实例化了它们两个.. ob2如何依赖并指向ob1的内存分配,而ob2应该从ob1的内存地址复制数据,而不是指向它.. (3认同)
  • 我无法理解你 '因为您没有将ob1分配给ob2,而是将其分配给变量a。 (2认同)
  • 通过将ob2分配给ob1,您将引用同一实例,即,在ob1字段中的任何更新都将反映在ob2字段中。 (2认同)
  • 你错误的内存分配概念.当你创建两个实例时,单独的内存分配就完成了指向自己的引用.但是一旦你将它们等同起来,它们就开始指向相同的参考.有关详细说明,请参阅此处 - http://stackoverflow.com/questions/7477073/made-one-instance-of-a-class-equal-to-another-how-to-cancel-that (2认同)
  • 哦..现在我明白了.非常感谢 !! (2认同)
  • @RohitVats 第一个代码片段对我来说甚至都不是浅拷贝。`ob2 = ob1;` 只是等同于引用(正如您在注释中输入的那样),根本不会发生复制。 (2认同)

Wil*_* Yu 16

在我看来,它不是严格的浅拷贝或深拷贝.如果我必须定义它,我会说浅拷贝.

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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

结果如下:

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
Run Code Online (Sandbox Code Playgroud)


EKa*_*ily 5

这既不是浅层也不是深层副本,这是一个引用copy.let我解释:有两种类型的变量:值类型和引用类型.

值类型是计算机内存中的(命名)位置,用于保存变量的实际值.例如:int是一个值类型,所以当你编写这行代码时:

int MyInt = 5;
Run Code Online (Sandbox Code Playgroud)

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

引用类型-in contrast-是内存中的(命名)位置,它实际上不保存变量的值,但保存该值存在的内存位置.例如,假设您编写了以下代码:

MyClass myObject = new MyClass();
Run Code Online (Sandbox Code Playgroud)

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

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

现在,如果您查看"myObject"变量,您将找不到类实例,但您会发现AA3D2表示保存该类实例的内存位置.

现在让我们检查给出OP的代码:

A ob1 = new A();
Run Code Online (Sandbox Code Playgroud)

这将创建一个名为ob1的变量,创建A类的实例并将该类的位置存储在ob1中

ob1.a = 10;
ob1.display();
Run Code Online (Sandbox Code Playgroud)

这将改变A类中的变量a.然后它调用display()方法

A ob2 = new A();
Run Code Online (Sandbox Code Playgroud)

在这里它创建一个名为ob2的变量,创建一个A类的实例并将其位置分配给ob2.

到目前为止,你在内存中有2个A和2个变量的类实例,每个变量都指向其中一个.现在这里是有趣的部分:ob2 = ob1;

变量ob2被赋予变量ob1的值.因为ob1包含A的第一个实例的内存位置,现在ob1和ob2都指向内存中的相同位置.使用其中一个做任何事情都与另一个完全相同.

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