.Net 对象的浅拷贝与深拷贝

浅拷贝

浅拷贝拷贝的是对象的引用,实际上还是指向同一个对象,改变其中任意对象的值,另一个对象的值也会跟着改变。

public class Animal
{
    public string Name { get; set; }
}

Animal a1 = new Animal() { Name = "小狗" };
Animal a2 = a1;                 // 这里就是浅拷贝
a2.Name = "小狗钱钱";           // 改变 a2.Name 的值
Console.WriteLine(a1.Name);     // 小狗钱钱,a1 跟着改变了,因为它们都指向同一个对象
Console.WriteLine(a2.Name);     // 小狗钱钱

深拷贝

简单的深拷贝

深拷贝就是连被引用的对象也拷贝一份出来,改变新拷贝对象的值不会影响原来对象的值。.Net中所有类型的根类定义了一个 protected 方法MemberwiseClone() ,使用这个方法可以实现简单的深拷贝

public class Employee
{
    public string Name { get; set; }

    public Employee Copy() => this.MemberwiseClone() as Employee;
}

Employee e1 = new Employee() { Name = "张三" };
Employee e2 = e1.Copy();

e2.Name = "李四";
Console.WriteLine(e1.Name);                     // 张三
Console.WriteLine(e2.Name);                     // 李四
Console.WriteLine(ReferenceEquals(e1, e2));     // False

由上面可以看出,改变拷贝对象(e2所指向的对象)的值不会影响 e1 所指向对象的值,再通过ReferenceEquals方法比较两个对象的引用,同样不相同,所以确实实现了“深拷贝”。

完全深拷贝

上面的深拷贝对象只有简单数据类型,如果引用了复杂的对象,那么MemberwiseClone方法还能完成“深拷贝”吗?

public class Employee
{
    public string Name { get; set; }

    public Dog Dog { get; set; }  // 新增复杂对象

    public Employee Copy() => this.MemberwiseClone() as Employee;
}

public class Dog
{
    public string Name { get; set; }
}

Dog dog = new Dog() { Name = "小狗钱钱" };
Employee e1 = new Employee() { Name = "张三", Dog = dog };
Employee e2 = e1.Copy();

e2.Name = "李四";
Console.WriteLine(e1.Name);                             // 张三
Console.WriteLine(e2.Name);                             // 李四
Console.WriteLine(ReferenceEquals(e1, e2));             // False

// 新增比较
e1.Dog.Name = "小狗";
Console.WriteLine(e1.Dog.Name);                         // 小狗
Console.WriteLine(e2.Dog.Name);                         // 小狗
Console.WriteLine(ReferenceEquals(e1.Dog, e2.Dog));     // True

由上面新增比较可以看出,引用了复杂对象类型的属性,使用MemberwiseClone方法进行拷贝时,并不能实现“完全的深拷贝”。实现“完全深拷贝”可以通过二进制格式序列化和反序列化的方式:

public static object Clone(object obj)
{
    using (MemoryStream ms = new MemoryStream())    // 创建内存流
    {
        BinaryFormatter bf = new BinaryFormatter(); // 以二进制格式进行序列化
        bf.Serialize(ms, obj);

        ms.Seek(0, 0);
        object res = bf.Deserialize(ms);            // 反序列化当前实例到一个object
        return res;
    }
}

Employee e3 = Clone(e1) as Employee;                    // 把 e1 拷贝到 e3
e1.Dog.Name = "小狗2";
Console.WriteLine(e1.Dog.Name);                         // 小狗2
Console.WriteLine(e3.Dog.Name);                         // 小狗1
Console.WriteLine(ReferenceEquals(e1, e3));             // False
Console.WriteLine(ReferenceEquals(e1.Dog, e3.Dog));     // False

好了,到这里可以看到,我们已经实现了“完全深拷贝”。

值类型的复制都可以看做是深拷贝。

References

MemberwiseClone创建一个浅表副本。过程是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型,则对该字段执行逐位复制;如果字段是引用类型,则复制引用但不复制引用对象。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
JavaScript中的对象拷贝分为浅拷贝深拷贝浅拷贝只是复制对象的引用地址,而不复制对象本身,因此对象还是指向同一个内存地址。而深拷贝则是创建一个全对象,包含了原始对象的所有属性和值。 浅拷贝常见的方法有使用Object.assign()方法或使用展开运算符(...)。例如,可以通过Object.assign()方法将原始对象的属性复制到一个空对象中来实现浅拷贝。这样,原始对象浅拷贝对象将指向不同的内存地址,修改其中一个对象不会影响另一个对象的值。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [javaScript对象深拷贝浅拷贝](https://blog.csdn.net/qq_50148250/article/details/127481075)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Js中对象深拷贝浅拷贝](https://blog.csdn.net/xuexizhe88/article/details/80989813)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Qanx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值