浅拷贝与深拷贝详解编程语言

前言

本文以C#为例,说明什么是浅拷贝,什么是深拷贝,以及如何应用序列化快速深拷贝。

目录

  • 浅拷贝与深拷贝简单说明
  • 浅拷贝
  • 复杂对象的浅拷贝
  • 深拷贝
  • 通过序列化深拷贝
  • 参考

浅拷贝与深拷贝简单说明

无论是浅拷贝与深拷贝,C#都将源对象中的所有字段复制到新的对象中。不过,对于值类型字段,引用类型字段以及字符串类型字段的处理,两种拷贝方式存在一定的区别。

拷贝类型 字段 拷贝操作详情 副本或源对象中修改是否相互影响
浅拷贝 值类型 字段被拷贝到副本中 不会
浅拷贝 引用类型 字段被拷贝到副本中
深拷贝 值类型 字段被重新创建并赋值 不会
深拷贝 引用类型 字段被重新创建并赋值 不会

浅拷贝

浅拷贝可以利用MemberwiseClone方法实现,具体代码如下:

using System; 
 
namespace CopyTest 
{ 
    public class Person : ICloneable 
    { 
        public string Name { get; set; } 
        public int Age { get; set; } 
 
        public Object Clone() 
        { 
            return this.MemberwiseClone() ; 
        } 
    } 
} 
 
using System; 
 
namespace CopyTest 
{ 
    public class PersonTest 
    { 
        public static void Test() 
        { 
            Test1(); 
            Test2(); 
        } 
 
        public static void Test1() 
        { 
            Person p1 = new Person(); 
            p1.Name = "zhao"; 
            p1.Age = 20; 
 
            Person p2 = p1; 
            p2.Name = "li"; 
            Console.WriteLine(p1.Name); 
        } 
 
        public static void Test2() 
        { 
            Person p1 = new Person(); 
            p1.Name = "zhao"; 
            p1.Age = 20; 
 
            Person p2 = p1.Clone() as Person; 
            p2.Name = "li"; 
            Console.WriteLine(p1.Name); 
        } 
 
    } 
} 
 

输出:

li 
zhao 

可见,通过浅拷贝,修改对象的值类型属性或字符串不影响拷贝对象;不浅拷贝只=是不行的。

复杂对象的浅拷贝

所谓复杂对象,指的是对象里面包含了对象(引用类型),而不是简单的值类型和字符串。比如:

using System; 
 
namespace CopyTest 
{ 
    public class Car:ICloneable 
    { 
        public string Name { get; set; } 
        public Person Driver { get; set; } 
 
        public object Clone() 
        { 
            return this.MemberwiseClone(); 
        } 
    } 
} 
 

这种情况下的浅拷贝是不会拷贝引用类型的。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
 
namespace CopyTest 
{ 
    class CarTest 
    { 
        public static void Test() 
        { 
            Car c1 = new Car(); 
            c1.Name = "audi"; 
            Person p1 = new Person(); 
            p1.Name = "wang"; 
            p1.Age = 20; 
            c1.Driver = p1;  
            Car c2 = c1.Clone() as Car; 
            c2.Name = "bmw"; 
            c2.Driver.Name = "li"; 
            Console.WriteLine(c1.Driver.Name); 
        } 
    } 
} 
 

输出

audi	li 

修改driver对c1有影响。解决这种问题,需要用深拷贝。

深拷贝

深拷贝需要单独写方法,代码如下:

using System; 
 
namespace CopyTest 
{ 
    public class NewCar : ICloneable 
    { 
        public string Name { get; set; } 
        public Person Driver { get; set; } 
 
        public object Clone() 
        { 
            NewCar ret = new NewCar(); 
            ret.Name = this.Name; 
            ret.Driver = new Person(); 
            ret.Driver.Name = this.Driver.Name; 
            ret.Driver.Age = this.Driver.Age; 
            return ret; 
        } 
    } 
} 
 

测试代码

using System; 
 
namespace CopyTest 
{ 
    public class NewCarTest 
    { 
        public static void Test() 
        { 
            NewCar c1 = new NewCar(); 
            c1.Name = "audi"; 
            Person p1 = new Person(); 
            p1.Name = "wang"; 
            p1.Age = 20; 
            c1.Driver = p1; 
            NewCar c2 = c1.Clone() as NewCar; 
            c2.Name = "bmw"; 
            c2.Driver.Name = "li"; 
            Console.WriteLine(c1.Driver.Name); 
        } 
    } 
} 
 

输出:

audi	wang 

通过序列化深拷贝

序列号的基本原理在这里不介绍了,我们可以应用序列号快速进行深拷贝,修改后的代码如下:

using System; 
using System.IO; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Formatters.Binary; 
 
namespace CopyTest 
{ 
    [Serializable] 
    public class NewCar : ICloneable 
    { 
        public string Name { get; set; } 
        public Person Driver { get; set; } 
 
        public object Clone() 
        { 
            using (Stream objectStream = new MemoryStream()) 
            { 
                IFormatter formatter = new BinaryFormatter(); 
                formatter.Serialize(objectStream, this); 
                objectStream.Seek(0, SeekOrigin.Begin); 
                return formatter.Deserialize(objectStream); 
            } 
        } 
    } 
} 
 

参考

例说C#深拷贝与浅拷贝

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/8903.html

(0)
上一篇 2021年7月19日 08:58
下一篇 2021年7月19日 08:58

相关推荐

发表回复

登录后才能评论