C# 对象深拷贝、浅铐贝、直接拷贝 【转】
原文:http://www.cnblogs.com/chjw8016/archive/2008/02/24/1078585.html
C#中有两种类型变量,一种是值类型变量,一种是引用类型变量。对于前者,copy是属于全盘复制;而对于后者,一般的copy只是浅copy,相当于只传递一个引用指针一样。因此对于后者进行真正copy的时候,也是最费事的,具体的说,必须为其实现ICloneable接口中提供的Clone方法。
浅拷贝(影子克隆):只复制对象的基本类型,对象类型,仍属于原来的引用.
深拷贝(深度克隆):不紧复制对象的基本类,同时也复制原对象中的对象.就是说完全是新对象产生的.
浅拷贝和深拷贝之间的区别:浅拷贝是指将对象中的数值类型的字段拷贝到新的对象中,而对象中的引用型字段则指复制它的一个引用到目标对象。如果改变目标对象中引用型字段的值他将反映在原是对象中,也就是说原始对象中对应的字段也会发生变化。深拷贝与浅拷贝不同的是对于引用的处理,深拷贝将会在新对象中创建一个新的和原是对象中对应字段相同(内容相同)的字段,也就是说这个引用和原是对象的引用是不同的,我们在改变新对象中的这个字段的时候是不会影响到原始对象中对应字段的内容。所以对于原型模式也有不同的两种处理方法:对象的浅拷贝和深拷贝。
MemberwiseClone 方法创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。深拷贝,即实现ICloneable接口.ICloneable可用于深拷贝和浅拷贝。
示例代码如下:
class Program
{
public class Sex
{
private string _PSex;
public string PSex
{
set
{
_PSex = value;
}
get
{
return _PSex;
}
}
}
public class Person : ICloneable
{
private Sex _pSex = new Sex();
public string pSex
{
set
{
_pSex.PSex = value;
}
get
{
return _pSex.PSex;
}
}
private string _PName;
public string PName
{
set
{
this._PName = value;
}
get
{
return this._PName;
}
}
public void ShowPersonInfo()
{
Console.WriteLine("-------------------------");
Console.WriteLine("Name:{0} Sex:{1}", _PName,this .pSex );
Console.WriteLine("-------------------------");
}
//浅拷贝
public object Clone()
{
return this.MemberwiseClone();
}
//深拷贝
public object DeepClone()
{
Person newP = new Person();
newP.PName = this._PName;
newP.pSex = this.pSex ;
return newP;
}
}
static void Main(string[] args)
{
Console.WriteLine("原对象:");
Person p = new Person();
p.PName = "JackLee";
p.pSex = "男";
p.ShowPersonInfo();
//浅拷贝
Person copy = (Person)p.Clone();
//深拷贝
Person dcopy = (Person)p.DeepClone();
Console.WriteLine("修改后的原对象:");
p.PName = "JackZhao";
p.pSex = "女";
p.ShowPersonInfo();
Console.WriteLine("修改后的浅拷贝对象:");
copy.ShowPersonInfo();
Console.WriteLine("修改后的深拷贝对象:");
dcopy.ShowPersonInfo();
Console.WriteLine("直接拷贝对象:");
Person PP = p;
PP.ShowPersonInfo();
Console.ReadLine();
}
}
运行结果如下:
说明:当然对于深拷贝还可以有其它的实现,比如说用序列化的方法等等。
在JavaScript中的也有对象的浅拷贝与深拷贝,看下面的例子:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
</HEAD>
<BODY>
<SCRIPT LANGUAGE="JavaScript">
<!--
function Object.prototype.clone(){
var newObj = new Object();
for(elements in this){
newObj[elements] = this[elements];
}
return newObj;
}
function Object.prototype.cloneAll(){
function clonePrototype(){}
clonePrototype.prototype = this;
var obj = new clonePrototype();
for(var ele in obj){
if(typeof(obj[ele])=="object") obj[ele] = obj[ele].cloneAll();
}
return obj;
}
var obj1 = new Object();
obj1.Team = "First";
obj1.Powers = new Array("Iori","Kyo");
obj1.msg = function(){alert()};
obj1.winner = new Object();
obj1.winner.name = obj1.Powers[0];
obj1.winner.age = 23;
obj1.winner.from = "Japan"
var obj1_clone = obj1.cloneAll();
obj1_clone.Team = "Second";
obj1_clone.Powers = new Array("Jimmy","Anndy");
obj1_clone.winner.name = obj1_clone.Powers[1];
obj1_clone.winner.age = 22;
obj1_clone.winner.from = "USA";
msg = "2003界拳皇单打独斗杯,拳皇挑战赛: \n\n A组 对战形式:\n\n"
msg += obj1.Team+" 组 ,人员名单:"+obj1.Powers+"\n";
msg += "第一轮过后,胜利者为:"+obj1.winner.name +" ,参赛者年龄:"+obj1.winner.age+" ,来自岛国: "+obj1.winner.from+"\n";
msg += "\n\n B组 对战形式:\n\n"
msg += obj1_clone.Team+" 组 ,人员名单:"+obj1_clone.Powers+"\n";
msg += "第一轮过后,胜利者为:"+obj1_clone.winner.name +" ,参赛者年龄:"+obj1_clone.winner.age+" ,来自国际警察部队: "+obj1_clone.winner.from+"\n";
alert(msg);
//-->
</SCRIPT>
</BODY>
</HTML>