C#中的浅拷贝(Shallow Copy)和深拷贝(Deep Copy),深拷贝的集中实现方式,浅拷贝深拷贝的案例

发布于:2024-04-27 ⋅ 阅读:(23) ⋅ 点赞:(0)

C#中的浅拷贝(Shallow Copy)和深拷贝(Deep Copy)

拷贝就是创建一个对象,这个对象有着原始对象数据(属性和字段)的一份精确拷贝(只针对ObjectArray这样的引用数据类型)。
换个说法就是:所谓的对象拷贝(复制)就是为对象创建副本,得到相同的对象。

浅拷贝(又称为影子拷贝):(1)如果对象属性的值是值类型和string类型,拷贝的就是基本类型的值;
(2)如果对象属性是引用类型,拷贝的就是引用类型(string除外)的引用(也就是堆地址);所以修改其中一个对象引用类型数据,会影响到另一个对象;
(3)浅拷贝使用的是Object.MemberwiseClone()方法。

浅拷贝出来的副本对象中,对象里的数据(属性和字段)如果是值类型和string类型,栈中保存的就是数据自身,在原始对象和副本对象中修改值类型数据,不会相互影响(因为值类型自身在栈中有不同的内存空间);如果是引用类型,浅拷贝只是拷贝引用类型的引用(也就是堆地址),所以在原始对象和副本对象中修改引用类型数据,会相互影响(因为原始对象和副本对象拥有同一个堆地址的引用)。
在这里插入图片描述
深拷贝:(1)完全将对象中的所有数据(属性和字段)都复制到副本对象中;
(2)引用类型的数据(属性和字段)会被重新创建并且复制;所以修改其中一个对象引用类型数据,不会影响到另一个对象。

深拷贝出来的副本对象中,对象里的数据(属性和字段)如果是值类型和string类型,栈中保存的就是数据自身在原始对象和副本对象中修改值类型数据,不会相互影响(因为值类型自身在栈中有不同的内存空间);如果是引用类型,深拷贝会重新创建引用类型的数据(属性和字段)并且复制原始对象中引用类型的数据的值(堆地址中保存的具体的值),所以在原始对象和副本对象中修改引用类型数据,不会相互影响。
在这里插入图片描述

浅拷贝和深拷贝在复制原型设计模式中的对象中起着重要作用。

C#中实现深拷贝的几种方式:
1.创建一个构造函数,在构造函数中将原始对象的值一一赋值给新对象。(当对象中的变量较少的话,可以使用)

2.首先浅拷贝对象,然后重新创建对象中的引用类型的变量。

3.通过对象的序列化和反序列化功能
(1)二进制序列化和反序列化
(2)xml序列化和反序列化
(3)Json序列化和反序列化

4.通过反射和递归实现

浅拷贝和深拷贝的示例代码:

namespace ShallowAndDeepCopy
{
    internal class Program
    {
        //年级
        public class Grade
        {
            public int Stu_Grade { get; set; }
        }

        //学生
        public class Student
        {
            public string Name { get; set; }

            public int Age { get; set; }

            public Grade Grade { get; set; }

            //调用Object的MemberwiseClone方法实现浅拷贝
            public Student ShallowCopy()
            {
                return (Student)this.MemberwiseClone();
            }

            //实现深拷贝的一种方式
            //通过浅拷贝拷贝了值类型的数据
            //重新新建引用类型变量
            public Student DeepCopy(int stu_Grade)
            {
                Student student = (Student)this.MemberwiseClone();
                student.Grade = new Grade() { Stu_Grade = stu_Grade };
                return student;
            }
        }

        private static void Main(string[] args)
        {
            Console.WriteLine("-----------------下面是浅拷贝深拷贝的测试代码----------------");

            //创建一个原始学生对象stu1并初始化所有字段
            Student stu1 = new Student();
            stu1.Name = "张三";
            stu1.Age = 18;
            stu1.Grade = new Grade() { Stu_Grade = 8 };

            //声明一个学生对象,保存stu1浅拷贝的副本对象的信息
            Student stu2 = stu1.ShallowCopy();
            Console.WriteLine("浅拷贝后stu1和stu2学生信息输出:");
            Console.WriteLine("学生stu1的信息:");
            //输出学生信息
            OutStuMsg(stu1);
            Console.WriteLine("学生stu2的信息:");
            //输出学生信息
            OutStuMsg(stu2);

            //修改浅拷贝副本对象的信息
            stu2.Name = "李四";
            stu2.Age = 20;
            stu2.Grade.Stu_Grade = 9;
            Console.WriteLine("浅拷贝后修改stu2学生后stu1和stu2信息输出:");
            Console.WriteLine("学生stu1的信息:");
            //输出学生信息
            OutStuMsg(stu1);
            Console.WriteLine("学生stu2的信息:");
            //输出学生信息
            OutStuMsg(stu2);

            //声明一个学生对象,保存stu1浅拷贝的副本对象的信息
            Student stu3 = stu1.DeepCopy(7);
            Console.WriteLine("深拷贝后stu1和stu3信息输出:");
            Console.WriteLine("学生stu1的信息:");
            //输出学生信息
            OutStuMsg(stu1);
            Console.WriteLine("学生stu3的信息:");
            //输出学生信息
            OutStuMsg(stu3);

            //修改深拷贝副本对象的信息
            stu3.Name = "王麻子";
            stu3.Age = 25;
            stu3.Grade.Stu_Grade = 10;
            Console.WriteLine("深拷贝后修改stu3学生后stu1和stu3信息输出:");
            Console.WriteLine("学生stu1的信息:");
            //输出学生信息
            OutStuMsg(stu1);
            Console.WriteLine("学生stu3的信息:");
            //输出学生信息
            OutStuMsg(stu3);
        }

        public static void OutStuMsg(Student student)
        {
            Console.WriteLine($"姓名:{student.Name}    年龄:{student.Age}");
            Console.WriteLine($"年级:{student.Grade.Stu_Grade} \n");
        }
    }
}

运行结果:
在这里插入图片描述
参考文章:
http://t.csdnimg.cn/qLenZ
https://docs.microsoft.com/zh-tw/dotnet/api/system.object.memberwiseclone?view=net-6.0


网站公告

今日签到

点亮在社区的每一天
去签到