深拷贝与浅拷贝(Deep Copy and Shallow Copy)

作者:Frank Xu Lei出处:博客2011-08-01 14:54

  我今天就在总结一下,并且添加了详细的代码实现,与大家分享。一起学习一下C#的深拷贝与浅拷贝(Deep Copy and Shallow Copy)的机制。全文还是分四部分:1.基本概念 2.深拷贝与浅拷贝实现机制 3.代码实现和分析 4.总结。下面我们来进入正式的学习。

  1.基本概念:

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

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

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

  我们知道,在C++中有拷贝构造函数和拷贝赋值函数的概念。浅拷贝就是成员数据之间的一一赋值:把值赋给一一赋给要拷贝的值。但是可能会有这样的情况:对象还包含资源,这里的资源可以指堆资源,或者一个文件。当值拷贝的时候,两个对象就有用共同的资源,同时对资源可以访问,这样就会出问题。深拷贝就是用来解决这样的问题的,它把资源也赋值一次,使对象拥有不同的资源,但资源的内容是一样的。对于堆资源来说,就是在开辟一片堆内存,把原来的内容拷贝。

  如果你拷贝的对象中引用了某个外部的内容(比如分配在堆上的数据),那么在拷贝这个对象的时候,让新旧两个对象指向同一个外部的内容,就是浅拷贝;如果在拷贝这个对象的时候为新对象制作了外部对象的独立拷贝,就是深拷贝

  这个C#里的概念与C++类似。我们可以参考以前的概念理解。 深拷贝与浅拷贝之间的区别基本可以从定义看出。首先浅拷贝是指将对象中的数值类型的字段拷贝到新的对象中,而对象中的引用型字段则指复制它的一个引用到目标对象。如果改变目标对象中引用型字段的值他将反映在原是对象中,也就是说原始对象中对应的字段也会发生变化。

  深拷贝与浅拷贝不同的是对于引用拷贝的处理,深拷贝将会在新对象中创建和原是对象中对应值类型的字段并且赋值。浅拷贝不会创建新引用类型,会返回相同的类型引用。深拷贝会重新创建新对象,返回新对象的引用字。C#中的观察者模式就是浅拷贝的例子。我们保留的只是对象的副本。

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

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

  对于值类型:

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

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

  对于引用类型:

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

  b.深拷贝:拷贝对象应用,也拷贝对象实际内容,也就是创建了一个新的改变新对象 不会影响到原始对象的内容

  这种情况需要为其实现ICloneable接口中提供的Clone方法。

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

  3.代码实现和分析:

  下面我们来看看具体的代码实现部分,首先介绍的还是值类型的。

  a.值类型浅拷贝的实现。代码如下:

以下是代码片段:
/// <summary> 
/// 数组的=赋值(直接拷贝),也就是引用传递,指向的是同一个地址: 
/// </summary> 
public void MethodShallowCopyDirectly() 

int[] ArrayInt = { 0, 1, 2, 3 }; 
//所以改变其中任意一个变量的值,另一个也会被改变 
int[] NewArrayInt = ArrayInt; 
//改变新的数组变量: 
NewArrayInt[0] = 8; 
Console.WriteLine("数组的复制(直接拷贝),改变新数组第一值为8,原值{0},新值{1}", ArrayInt[0], NewArrayInt[0]); 

/// <summary> 
/// ArrayInt.CopyTo,创建以个新数组,不影响原来的值 
/// </summary> 
public void MethodShallowCopyArrayCopyTo() 

int[] ArrayInt = { 0, 1, 2, 3 }; 
//CopyTo()方法 
int[] NewArrayInt = new int[5];//创建以个新数组,按值拷贝,不影响原来的值 
ArrayInt.CopyTo(NewArrayInt, 0); 
NewArrayInt[0] = 8; 
Console.WriteLine("Array.CopyTo,改变新数组第一值为8,原值{0},新值{1}", ArrayInt[0], NewArrayInt[0]);

/// <summary> 
/// Array.Copy浅拷贝,值类型的浅拷贝,创建以个新数组,按值拷贝,不影响原来的值 
/// </summary> 
public void MethodShallowCopyArrayCopy() 

int[] ArrayInt = { 0, 1, 2, 3 }; 
//Copy()方法 
int[] NewArrayInt = new int[4]; 
Array.Copy(ArrayInt, NewArrayInt, 0);//创建以个新数组,按值拷贝,不影响原来的值 
NewArrayInt[0] = 8; 
Console.WriteLine("Array.Copy,改变新数组第一值为8,原值{0},新值{1}", ArrayInt[0], NewArrayInt[0]); 

/// <summary> 
/// Array.Clone(),浅拷贝 
/// </summary> 
public void MethodShallowCopyArrayClone() 

int[] ArrayInt = { 0, 1, 2, 3 }; 
//Array Clone()方法 
int[] NewArrayInt = ArrayInt.Clone() as int[];//按值拷贝,不影响原来的值 
NewArrayInt[0] = 8; 
Console.WriteLine("Array.Clone(),改变新数组第一值为8,原值{0},新值{1}", ArrayInt[0], NewArrayInt[0]); 

/// <summary> 
/// .浅拷贝:(引用类型),数组中的元素是引用类型,复制的是它的一个引用,改变新拷贝会改变原对象 
/// </summary> 
public void MethodShallowCopyStringArrayCopyTo() 

string[] sArray ={ "string0", "string1", "string2" }; 
string[] sNewArray = sArray; 
//浅拷贝一个新对象 
sArray.CopyTo(sNewArray, 0); 
//改变新对象的值这个时候源对象中的值也会被改变 
sNewArray[0] = "FrankXuLei"; 
Console.WriteLine("数组的浅拷贝:(引用类型),改变第一值为FrankXuLei,原值{0},新值{1}", sArray[0], sNewArray[0]); 

/// <summary> 
/// //字符串数组的深拷贝,如果需要包含引用类型的数组的深副本,就必须迭代数组,创建新对象 
/// </summary> 
public void MethodDeepCopyStringArray() 

string[] sArray = new string[] { "string0", "string1", "string2", "string3" }; 
string[] sNewArray = new string[4];//迭代数组,创建新对象 
for (int i = 0; i < sArray.Length; i++) 

string sTemp = string.Empty; 
sTemp = sArray[i]; 
sNewArray[i] = sTemp; 

sNewArray[0] = "FrankXuLei"; 
Console.WriteLine("数组的复制(直接拷贝),改变新数组第一值为FrankXuLei,原值{0},新值{1}", sArray[0], sNewArray[0]); 
}

  数组的=赋值(直接拷贝),也就是引用传递,指向的是同一个地址,所以改变其中任意一个变量的值,另一个也会被改变。ArrayInt.CopyTo,创建以个新数组,改变新的数组变量不影响原来的值。Array.Copy浅拷贝,值类型的浅拷贝,创建以个新数组,按值拷贝,不影响原来的值。 .浅拷贝:(引用类型),数组中的元素是引用类型,复制的是它的一个引用,改变新拷贝会改变原对象.

 4.总结

  通过以上内容的学习,希望大家对C#中的深拷贝与浅拷贝(Deep Copy and Shallow Copy)的机制能有更深入的了解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值