理解.NET 浅拷贝与深拷贝

Tips:

先引入一个观念,赋值和深复制、浅复制并不是一样的,含义是不一样的。

1.赋值。指的是 “ = ”。它相当于是给引用对象起一个别名。

2.浅拷贝和深拷贝。指的是类实现 ICloneable接口,重写该接口的唯一方法。注意:不管是深度复制还是浅度复制,都是通过ICloneable接口去实现的。

为对象创建副本的技术称为拷贝(也叫克隆)。我们将拷贝分为浅拷贝和深拷贝。

浅拷贝:将对象中的所有字段复制到新的对象(副本)中。其中,值类型字段的值

被复制到副本中后,在副本中的修改不会影响到源对象对应的值。而引用类型的字段被

复制到副本中的是引用类型的引用,而不是引用的对象,在副本中对引用类型的字段值

做修改会影响到源对象本身。

深拷贝:同样,将对象中的所有字段复制到新的对象中。不过,无论是对象的值类

型字段,还是引用类型字段,都会被重新创建并赋值,对于副本的修改,不会影响到源

对象本身。

无论是浅拷贝还是深拷贝,微软都建议用类型继承ICloneable接口的方式明确告诉

调用者:该类型可以被拷贝。当然,ICloneable接口只提供了一个声明为Clone的方法,

我们可以根据需求在Clone方法内实现浅拷贝或深拷贝。

示例代码:

        class Employee : ICloneable
        {
            public string IDCode { get; set; }
            public int Age { get; set; }
            public Department Department { get; set; }
            public object Clone()
            {
                return this.MemberwiseClone();
            }

        }

        class Department
        {
            public string Name { get; set; }
            public override string ToString()
            {
                return base.ToString();
            }
        }

调用代码:

            Employee mike = new Employee()
            {
                IDCode = "NB123",
                Age = 30,
                Department = new Department()
                {
                    Name = "Depl"
                }
            };
            Employee rose = mike.Clone() as Employee;
            Console.WriteLine(rose.IDCode);
            Console.WriteLine(rose.Age);
            Console.WriteLine(rose.Department.Name);
            Console.WriteLine("开始改变mike的值:");
            mike.IDCode = "NB456";
            mike.Age = 60;
            mike.Department.Name = "Dep2";
            Console.WriteLine(rose.IDCode);
            Console.WriteLine(rose.Age);
            Console.WriteLine(rose.Department.Name);

注意到Employee的IDCode属性是string类型。理论上string类型是引用类型,但是由于该引用类型的特殊性(无论是实现还是语义),Object.MemberwiseClone方法仍旧为其创建了副本。也就是说,在浅拷贝过程,我们应该将字符串看成是值类型。

Employee的Department属性是一个引用类型,所以,如果改变了源对象mike中的值,副本rose中的值也会随之一起变动。

Employee的深拷贝有多种实现方法,最简单的方法是手动对字段逐个进行赋值。但这种方法容易出错,也就是说,如果类型的字段发生变化或有增减,那么该拷贝方法也要发生相应的变化,所以,建议使用序列化的形式来进行深拷贝。Employee深拷贝的一个简单实现代码如下所示:

namespace TestProject
{
    internal class Program
    {
        private static async Task Main(string[] args)
        {

            Employee mike = new Employee()
            {
                IDCode = "NB123",
                Age = 30,
                Department = new Department()
                {
                    Name = "Depl"
                }
            };
            Employee rose = mike.Clone() as Employee;
            Console.WriteLine(rose.IDCode);
            Console.WriteLine(rose.Age);
            Console.WriteLine(rose.Department.Name);

            Console.WriteLine("开始改变mike的值:");

            mike.IDCode = "NB456";
            mike.Age = 60;
            mike.Department.Name = "Dep2";

            Console.WriteLine(rose.IDCode);
            Console.WriteLine(rose.Age);
            Console.WriteLine(rose.Department.Name);
            Console.ReadKey();
        }
        [Serializable]
        class Employee : ICloneable
        {
            public string IDCode { get; set; }
            public int Age { get; set; }
            public Department Department { 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) as Employee;
                }
            }

        }

        [Serializable]
        class Department
        {
            public string Name { get; set; }
            public override string ToString()
            {
                return base.ToString();
            }
        }
    }
}

可以发现,再次更改mike的值已经不会影响副本rose的值了。由于接口ICloneable只有一个模棱两可的Clone方法,所以,如果要在一个类中同时实现深拷贝和浅拷贝,只能由我们自己实现两个额外的方法,声明为DeepClone和

Shallow。Employee的最终版本看起来应该像如下的形式:

        [Serializable]
        class Employee : ICloneable
        {
            public string IDCode { get; set; }
            public int Age { get; set; }
            public Department Department { get; set; }
            public object Clone()
            {
                //浅拷贝
                return this.MemberwiseClone();
            }

            public Employee DeepClone()
            {
                //深拷贝
                using (Stream objectStream = new MemoryStream())
                {
                    IFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(objectStream, this);
                    objectStream.Seek(0, SeekOrigin.Begin);
                    return formatter.Deserialize(objectStream) as Employee;
                }
            }

            public Employee ShallowClone()
            {
                return Clone() as Employee;
            }

        }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深拷贝浅拷贝是在对象拷贝过程中所使用的两种不同的方法。深拷贝会创建一个新的对象,并递归地复制所有嵌套的对象,包括对象的所有属性。这意味着,新对象与原始对象是完全独立的,对新对象的修改不会影响原始对象。 浅拷贝则是创建一个新的对象,但是只复制原始对象的引用,而不复制嵌套对象本身。这意味着,新对象与原始对象共享相同的嵌套对象,对新对象或原始对象的嵌套对象进行修改都会互相影响。 在Python中,可以使用copy模块中的copy()函数来进行浅拷贝,使用deepcopy()函数来进行深拷贝。例如,对于列表a,可以使用copy.copy(a)进行浅拷贝,使用copy.deepcopy(a)进行深拷贝。 总结起来,深拷贝会创建一个新的对象,并递归地复制所有嵌套对象,而浅拷贝复制原始对象的引用。因此,深拷贝会产生独立的对象,而浅拷贝则会共享嵌套对象。这就是深拷贝浅拷贝的区别。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [python的深拷贝浅拷贝](https://download.csdn.net/download/weixin_38644097/13749157)[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^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [让你彻底理解浅拷贝深拷贝的区别](https://blog.csdn.net/weixin_43878906/article/details/108358240)[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^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [浅拷贝深拷贝的区别](https://blog.csdn.net/m0_73770538/article/details/126898545)[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^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值