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


    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");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

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

  • 相关阅读:
    c++11 实现枚举值到枚举名的转换
    WebAPI文档与自动化测试
    Textpad 缺少Java编译和运行功能
    docker基本管理
    定时任务相关
    C. Road Optimization(dp)
    第一次使用idea运行报错,说构建失败
    [报告] Microsoft :Application of deep learning methods in speech enhancement
    C++11之防止类型收窄(列表初始化)
    《Go程序员面试笔试宝典》第四章 · 通道书评
  • 原文地址:https://blog.csdn.net/weixin_43603714/article/details/137829763