浅拷贝与深拷贝

前言

本文以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#深拷贝与浅拷贝

posted @ 2015-01-17 18:53  wardensky  阅读(242)  评论(0编辑  收藏  举报