不忘本~浅拷贝和深拷贝

简介:

Clone 分浅拷贝和深拷贝

两者的区别:当对象中的属性是引用类型时,即类product中还有对类category的引用时,浅拷贝与深拷贝才有区别。

浅拷贝:复制的是category的引用,当原对象改变时,会影响新对象,反之,亦然。

深拷贝:复制的是category的值,即,它会new一个新的category,然后将原来的category元素的值复制到新元素,即它与原对象没有任何关系,只是内容相同。

如何实现对象的拷贝功能:

继承接口ICloneable实现Clone方法 
 ICloneable.Clone本身并不能区分(Deep or Shallow)你可以在Clone中调用MemberwiseClone来实现一个ShallowClone也可以自己来实现一个DeepClone。不过按照microsoft的建议当实现ICloneable的时候是准备用来实现一个DeepClone。 
ICloneable.Clone返回类型是object 
其中MemberwiseClone的复制原理是值类型按位复制,引用类型复制对象的引用。这里有一个要注意的就是String类型,虽然是引用类型,不过在这里表现上和值类型是一样的,在Clone的时候就当作值类型来看待好了。

实现Clone的方法:

1. 手工克隆

一个能够保证对象完全按照你所想的那样进行克隆的方式是手工克隆对象的每一个域(field)。这种方式的缺点是麻烦而且容易出错:如果你在类中增加了一个域,你很可能会忘记更新Clone方法。还要在克隆引用对象指向原始对象的时候,注意避免无限循环引用。下面是一个进行深拷贝的简单例子:

 

2. 使用MemberWiseClone方法

MemberWiseClone是 Object类的受保护方法,能够通过创建一个新对象,并把所有当前对象中的非静态域复制到新对象中,从而创建一个浅拷贝。对于值类型的域,进行的是按位拷贝。对于引用类型的域,引用会被赋值而引用的对象则不会。因此,原始对象及其克隆都会引用同一个对象。注意,这种方法对派生类都是有效的,也就是说,你只需在基类中定义一次Clone方法。下面是一个简单的例子:

1 public class Person : ICloneable
2 {
3     public string Name;
4     public Person Spouse;
5     public object Clone()
6     {
7         return this.MemberwiseClone();
8     }
9 }

3. 用反射进行克隆

用反射进行克隆是使用Activator.CreateInstance方法来创建一个相同类型的新对象,然后用反射对所有域进行浅拷贝。这种方法的优点是它是全自动的,不需要在对象中添加或删除成员的时候修改克隆方法。另外它也能被写成提供深拷贝的方法。缺点是使用了反射,因此会比较慢,而且在部分受信任的环境中是不可用的。示例代码

4. 使用序列化进行克隆

克隆一个对象的最简单的方法是将它序列化并立刻反序列化为一个新对象。和反射方法一样,序列化方法是自动的,无需在对对象成员进行增删的时候做出修改。缺点是序列化比其他方法慢,甚至比用反射还慢,所有引用的对象都必须是可序列化的(Serializable)。另外,取决于你所使用的序列化的类型(XML,SOAP,二进制)的不同,私有成员可能不能像期望的那样被克隆。示例代码在这里这里这里

5. 使用IL进行克隆

一种罕见的解决方案是使用IL(中间语言)来进行对象克隆。这种方式创建一个动态方法(DynamicMethod),获取中间语言生成器(ILGenerator),向方法中注入代码,把它编译成一个委托,然后执行这个委托。委托会被缓存,因此中间语言只在初次克隆的时候才会生成,后续的克隆都不会重新生成一遍。尽管这种方法比使用反射快,但是这种方法难以理解和维护。示例代码

6. 使用扩展方法进行克隆

Havard Stranden用扩展方法(extention method)创建了一个自定义的克隆框架。这个框架能够创建对象及其引用的对象的深拷贝,不管对象结构有多复杂。缺点是,这是一个不提供源代码的自定义框架(更新:现在已经包括源代码了,参见本文评论),并且它不能在不使用无参数构造器的时候,拷贝由私有方法创建的对象。另一个问题,也是所有自动化的深克隆方法共有的问题是,深拷贝通常需要灵活地处理不能进行简单自动化特殊情况(例如未受管理的资源)。

本文转自博客园张占岭(仓储大叔)的博客,原文链接:不忘本~浅拷贝和深拷贝,如需转载请自行联系原博主。

目录
相关文章
|
Python 内存技术
分享81个个人模板,总有一款适合您
分享81个个人模板,总有一款适合您
152 0
|
弹性计算 Linux 数据中心
阿里云香港服务器30M大带宽24元1个月,288元一年
阿里云香港服务器30M大带宽24元1个月,288元一年,阿里云香港服务器2核1G、30M带宽、40GB ESSD系统盘优惠价格24元/月,288元一年,每月流量1024GB,多配置可选,阿里云百科整理分享阿里云香港服务器优惠活动、详细配置价格表和购买条件
|
数据安全/隐私保护
阿里云注销备案流程及注销备案常见问题与解答
网站域名如果不用了或者转移给他人阿里云百科网建议已经备案的域名及时注销备案,因为域名的备案信息还是你的,阿里云百科网分享注销备案的流程和方法及注销备案的常见问题与解答: 注销备案方法流程 相对于备案来讲,注销备案就简单的多了(可以参考官方文档:注销备案流程 - 阿里云),阿里云百科网以注销阿里云备案为例: 注销分类 网站备案注销有两类,即注销主体和注销网站: 注销主体:注销在阿里云备案的主体信息,并注销该主体下备案的所有网站服务; 注销网站:注销需要停止服务的网站备案信息,主体备案信息保留。
9929 0
|
前端开发 JavaScript .NET
一起谈.NET技术,Unobtrusive JavaScript in ASP.NET MVC 3
  Unobtrusive JavaScript 是什么? 测试测试   以上的代码分别是MVC3在“关闭”和“开启”Unobtrusive JavaScript 后生成的 Ajax.ActionLink。
1457 0
|
1天前
|
云安全 人工智能 自然语言处理
|
6天前
|
搜索推荐 编译器 Linux
一个可用于企业开发及通用跨平台的Makefile文件
一款适用于企业级开发的通用跨平台Makefile,支持C/C++混合编译、多目标输出(可执行文件、静态/动态库)、Release/Debug版本管理。配置简洁,仅需修改带`MF_CONFIGURE_`前缀的变量,支持脚本化配置与子Makefile管理,具备完善日志、错误提示和跨平台兼容性,附详细文档与示例,便于学习与集成。
316 116
|
8天前
|
数据采集 人工智能 自然语言处理
Meta SAM3开源:让图像分割,听懂你的话
Meta发布并开源SAM 3,首个支持文本或视觉提示的统一图像视频分割模型,可精准分割“红色条纹伞”等开放词汇概念,覆盖400万独特概念,性能达人类水平75%–80%,推动视觉分割新突破。
615 53
Meta SAM3开源:让图像分割,听懂你的话

热门文章

最新文章