.NET的堆和栈03,引用类型对象拷贝以及内存分配

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

在" .NET的堆和栈01,基本概念、值类型内存分配"中,了解了"堆"和"栈"的基本概念,以及值类型的内存分配。我们知道:当执行一个方法的时候,值类型实例会在"栈"上分配内存,而引用类型实例会在"堆"上分配内存,当方法执行完毕,"栈"上的实例由操作系统自动释放,"堆"上的实例由.NET Framework的GC进行回收。

在" .NET的堆和栈02,值类型和引用类型参数传递以及内存分配"中,我们了解了值类型参数和引用类型参数在传递时的内存分配情况。

而本篇的重点要放在:引用类型对象拷贝以及内存分配。

主要包括:

■ 引用类型对象拷贝 成员都是值类型

■ 引用类型对象拷贝 包含引用类型成员

引用类型对象拷贝 成员都是值类型

publicstructShoe{publicstringColor;

}publicclassDude

{publicstringName;publicShoe RightShoe;publicShoe LeftShoe;publicDude CopyDude()

{

Dude newPerson=newDude();

newPerson.Name=Name;

newPerson.LeftShoe=LeftShoe;

newPerson.RightShoe=RightShoe;returnnewPerson;

}publicoverridestringToString()

{return(Name +": Dude!, I have a"+ RightShoe.Color +"shoe on my right foot, and a"+LeftShoe.Color+"on my left foot.");

}

}publicstaticvoidMain()

{

Dude Bill=newDude();

Bill.Name="Bill";

Bill.LeftShoe=newShoe();

Bill.RightShoe=newShoe();

Bill.LeftShoe.Color= Bill.RightShoe.Color ="Blue";

Dude Ted=Bill.CopyDude();

Ted.Name="Ted";

Ted.LeftShoe.Color= Ted.RightShoe.Color ="Red";

Console.WriteLine(Bill.ToString());

Console.WriteLine(Ted.ToString());

}

输出结果:

Bill : Dude!, I have a Red shoe on my right foot, and a Red on my left foot

Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot

以上,当引用类型的属性、成员都是值类型的时候,拷贝是完全拷贝。

引用类型对象拷贝 包含引用类型成员

把Shoe由struct值类型改成引用类型class。

publicclassShoe{publicstringColor;

}

再次运行,输出结果:

Bill : Dude!, I have a Red shoe on my right foot, and a Red on my left foot

Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot

当Dude类包含引用类型属性Shoe的时候,在托管堆上的情况是这样的:

拷贝后,2个Dude的Shoe类型的属性指向了同一个托管堆内的Shoe实例,改变Shoe的值会同时影响到2个Dude。

很显然,这不是我们期望的完全拷贝,如何做到完全拷贝呢?

--实现ICloneable接口

ICloneable接口的Clone()方法,允许我们在拷贝的时候,进行一些自定义设置。

让引用类Shoe实现ICloneable接口。

publicclassShoe : ICloneable

{publicstringColor;publicobjectClone()

{

Shoe newShoe=newShoe();

newShoe.Color= Color.Clone()asstring;returnnewShoe;

}

}

以上,Shoe的string类型属性Color之所以可以使用Color.Clone()方法,是因为string也实现了ICloneable接口;又由于Clone()返回类型是object,所以,在使用Color.Clone()方法之后,需要把object转换成string类型。

现在,在Dude类的CopyDude()方法中,当拷贝Shoe类型属性的时候,就可以使用Shoe独有的拷贝方法Clone()。

publicDude CopyDude()

{

Dude newPerson=newDude();

newPerson.Name=Name;

newPerson.LeftShoe= LeftShoe.Clone()asShoe;

newPerson.RightShoe= RightShoe.Clone()asShoe;returnnewPerson;

}

客户端程序。

publicstaticvoidMain()

{

Dude Bill=newDude();

Bill.Name="Bill";

Bill.LeftShoe=newShoe();

Bill.RightShoe=newShoe();

Bill.LeftShoe.Color= Bill.RightShoe.Color ="Blue";

Dude Ted=Bill.CopyDude();

Ted.Name="Ted";

Ted.LeftShoe.Color= Ted.RightShoe.Color ="Red";

Console.WriteLine(Bill.ToString());

Console.WriteLine(Ted.ToString());

}

输出结果:

Bill : Dude!, I have a Blue shoe on my right foot, and a Blue on my left foot

Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot

这正是我们期望的完全拷贝!

完全拷贝,托管堆上的情况是这样的:

当然也可以让同时包含值类型和引用类型成员,同时需要拷贝的类实现ICloneable接口。

publicclassDude: ICloneable

{publicstringName;publicShoe RightShoe;publicShoe LeftShoe;publicoverridestringToString()

{return(Name +": Dude!, I have a"+ RightShoe.Color +"shoe on my right foot, and a"+LeftShoe.Color+"on my left foot.");

}#regionICloneable MemberspublicobjectClone()

{

Dude newPerson=newDude();

newPerson.Name= Name.Clone()asstring;

newPerson.LeftShoe= LeftShoe.Clone()asShoe;

newPerson.RightShoe= RightShoe.Clone()asShoe;returnnewPerson;

}#endregion}

客户端调用。

publicstaticvoidMain()

{

Class1 pgm=newClass1();

Dude Bill=newDude();

Bill.Name="Bill";

Bill.LeftShoe=newShoe();

Bill.RightShoe=newShoe();

Bill.LeftShoe.Color= Bill.RightShoe.Color ="Blue";

Dude Ted= Bill.Clone()asDude;

Ted.Name="Ted";

Ted.LeftShoe.Color= Ted.RightShoe.Color ="Red";

Console.WriteLine(Bill.ToString());

Console.WriteLine(Ted.ToString());

}

输出结果:

Bill : Dude!, I have a Blue shoe on my right foot, and a Blue on my left foot.

Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot.

也是我们期望的完全拷贝!

参考资料:

C# Heap(ing) Vs Stack(ing) in .NET: Part III

".NET的堆和栈"系列包括:

.NET的堆和栈01,基本概念、值类型内存分配.NET的堆和栈02,值类型和引用类型参数传递以及内存分配.NET的堆和栈03,引用类型对象拷贝以及内存分配.NET的堆和栈04,对托管和非托管资源的垃圾回收以及内存分配

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航