C#中的深拷贝与浅拷贝

时间:2021-03-10 13:33:13

1.基本的概念:

首先我们应该了解一下什么叫深拷贝与浅拷贝(Deep Copy and Shallow Copy)。

a.浅拷贝(Shallow Copy影子克隆):只复制对象的基本类型,对象类型,仍属于原来的引用。

b.深拷贝(Deep Copy 深度克隆):不紧复制对象的基本类,同时也复制原对象中的对象.完全产生新对象。

深拷贝与浅拷贝不同的是对于引用拷贝的处理,深拷贝将会在新对象中创建和原是对象中对应值类型的字段并且赋值。浅拷贝不会创建新引用类型,会返回相同的类 型引用。深拷贝会重新创建新对象,返回新对象的引用字。

2.深拷贝与浅拷贝实现机制:

从上面的概念我们了解了C#深拷贝与浅拷贝(Deep Copy and Shallow Copy)的不同之处。这个也就决定了两者有不同的实现方式。

对于值类型:

a.浅拷贝: 通过赋值等操作直接实现,将对象中的值类型的字段拷贝到新的对象中。
b.深拷贝:通过赋值等操作直接实现,将对象中的值类型的字段拷贝到新的对象中。 和浅拷贝相同

对于引用类型:

a.浅拷贝: MemberwiseClone 方法创建一个浅副本,方法是创建一个新对象,如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用原始对象,与原对象引用同一对象。

b.深拷贝:拷贝对象应用,也拷贝对象实际内容,也就是创建了一个新的改变新对象 不会影响到原始对象的内容
这种情况需要为其实现ICloneable接口中提供的Clone方法。

差别就是在对于引用类型的实现深拷贝和浅拷贝的时候的机制不同,前者是MemberwiseClone 方法实现,后者是通过继承实现ICloneable接口中提供的Clone方法,实现对象的深入拷贝。

3.代码实现

浅拷贝实例:

C# 代码   复制
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝using System;
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝namespace Prototype_Shallow{
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 //因为我们在FCL里面已经有这样的接口所以我们就不定义新的Prototype了
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public class ConcretePrototype1 : ICloneable{
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 private int m_ID;
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public int ID{
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 get{
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 return this.m_ID;
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public ConcretePrototype1(int id){
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 this.m_ID = id;
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public object Clone(){
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 return this.MemberwiseClone();
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public class ConcretePrototype2 : ICloneable{
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 private int m_ID;
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public int ID
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 {
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 get
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 {
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 return this.m_ID;
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public ConcretePrototype2(int id){
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 this.m_ID = id;
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public object Clone(){
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 return this.MemberwiseClone();
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝}
C#中的深拷贝与浅拷贝

代码说明:

我们具体的原型都继承了接口ICloneable,同时也实现了该接口里面唯一个一个方法Clone。我们可以在客户端这样创建对象ConcretePrototype1 p1 = new ConcretePrototype1(1);

ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();

首先我们创建了对象p1,接下来我们用通过p1的科隆方法得到了对象c1,这就是一种浅拷贝(因为MemberwiseClone是浅拷贝)。

深拷贝实例:

 
C# 代码   复制
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝namespace Prototype_Deep{
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 using System.Collections;
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public class ConcretePrototype : ICloneable
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 {
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 private int m_ID;
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public int ID
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 {
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 get
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 {
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 return this.m_ID;
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 private ArrayList m_arrayList = new ArrayList();
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public ConcretePrototype(int id)
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 {
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 this.m_ID = id;
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 this.m_arrayList.Add("FirstObject");
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 this.m_arrayList.Add("SecondObject");
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 // ...
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public object Clone()
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 {
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 ConcretePrototype c = new ConcretePrototype(this.ID);
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 c.m_arrayList = new ArrayList();
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 c.m_arrayList.Add("FirstObject");
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 c.m_arrayList.Add("SecondObject");
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 return c;
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 public ConcretePrototype DeepClone(){
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 return (ConcretePrototype)this.Clone();
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝 }
C#中的深拷贝与浅拷贝
C#中的深拷贝与浅拷贝}

代码说明:

该代码显示了如何实现深拷贝,深拷贝的原则就是对于那些引用的字段您需要new(new之前想想是不是能用前面学过的某个创建型的模式实现,这是一个好的习惯)一个出来,然后对该字段里面的对象一一拷贝,这样以来很容易出现循环拷贝,所以说深拷贝要比浅拷贝更难一些。

客户端可以通过

ConcretePrototype p = new ConcretePrototype(1);

ConcretePrototype c = p.DeepClone();

来实现克隆一个新的对象。