C#对象克隆介绍
浅拷贝和深拷贝
有两种对象克隆的方法:浅拷贝和深拷贝。浅拷贝只是复制引用,而不会复制引用的对象。深拷贝会复制引用的对象。
因此,原始对象中的引用和浅拷贝对象中的同一个引用都指向同一个对象。而深拷贝的对象包含了对象的一切直接或间接的引用。参看维基百科(http://en.wikipedia.org/wiki/Object_copy)来获得更多解释。
ICloneable接口
ICloneable接口包含一个Clone方法,可以用来创建当前对象的拷贝。
{
object Clone();
}
ICloneable的问题是Clone方法并不会显式地指定是执行浅拷贝或深拷贝,因此调用者将无法确定实际情况。因此,有一些关于把ICloneable从.NET框架中淘汰的讨论。MSDN文档似乎暗示Clone方法是进行的深拷贝,但是文档没有明确的说明:
ICloneable接口包含一个成员方法,Clone,意在支持超过MemberWiseClone所提供的功能... MemberWiseClone进行的是浅拷贝...
类型安全的克隆
ICloneable的另一个缺点是Clone方法返回的是一个对象,因此每次调用Clone都要进行一次强制类型转换。
joe.Name = "Joe Smith";
Person joeClone = (Person)joe.Clone();
一种可以避免进行强制类型转换的方式是提供你自己的类型安全的Clone方法。注意,你依然要提供ICloneable.Clone方法的以满足iCloneable接口的要求。
{
public string Name;
object ICloneable.Clone()
{
return this.Clone();
}
public Person Clone()
{
return (Person)this.MemberwiseClone();
}
}
选择克隆方法
1. 手工克隆
一个能够保证对象完全按照你所想的那样进行克隆的方式是手工克隆对象的每一个域(field)。这种方式的缺点是麻烦而且容易出错:如果你在类中增 加了一个域,你很可能会忘记更新Clone方法。还要在克隆引用对象指向原始对象的时候,注意避免无限循环引用。下面是一个进行深拷贝的简单例子:
{
public string Name;
public Person Spouse;
public object Clone()
{
Person p = new Person();
p.Name = this.Name;
if (this.Spouse != null)
p.Spouse = (Person)this.Spouse.Clone();
return p;
}
}
2. 使用MemberWiseClone方法
MemberWiseClone是Object类的受保护方法,能够通过创建一个新对象,并把所有当前对象中的非静态域复制到新对象中,从而创建一 个浅拷贝。对于值类型的域,进行的是按位拷贝。对于引用类型的域,引用会被赋值而引用的对象则不会。因此,原始对象及其克隆都会引用同一个对象。注意,这 种方法对派生类都是有效的,也就是说,你只需在基类中定义一次Clone方法。下面是一个简单的例子:
{
public string Name;
public Person Spouse;
public object Clone()
{
return this.MemberwiseClone();
}
}
3. 用反射进行克隆
用反射进行克隆是使用Activator.CreateInstance方法来创建一个相同类型的新对象,然后用反射对所有域进行浅拷贝。这种方法 的优点是它是全自动的,不需要在对象中添加或删除成员的时候修改克隆方法。另外它也能被写成提供深拷贝的方法。缺点是使用了反射,因此会比较慢,而且在部 分受信任的环境中是不可用的。示例代码
4. 使用序列化进行克隆
克隆一个对象的最简单的方法是将它序列化并立刻反序列化为一个新对象。和反射方法一样,序列化方法是自动的,无需在对对象成员进行增删的时候做出修 改。缺点是序列化比其他方法慢,甚至比用反射还慢,所有引用的对象都必须是可序列化的(Serializable)。另外,取决于你所使用的序列化的类型 (XML,SOAP,二进制)的不同,私有成员可能不能像期望的那样被克隆。示例代码在这里,这里和这里。
5. 使用IL进行克隆
一种罕见的解决方案是使用IL(中间语言)来进行对象克隆。这种方式创建一个动态方法(DynamicMethod),获取中间语言生成器 (ILGenerator),向方法中注入代码,把它编译成一个委托,然后执行这个委托。委托会被缓存,因此中间语言只在初次克隆的时候才会生成,后续的 克隆都不会重新生成一遍。尽管这种方法比使用反射快,但是这种方法难以理解和维护。示例代码
6. 使用扩展方法进行克隆
Havard Stranden用扩展方法(extention method)创建了一个自定义的克隆框架。这个框架能够创建对象及其引用的对象的深拷贝,不管对象结构有多复杂。缺点是,这是一个不提供源代码的自定义 框架(更新:现在已经包括源代码了,参见本文评论),并且它不能在不使用无参数构造器的时候,拷贝由私有方法创建的对象。另一个问题,也是所有自动化的深 克隆方法共有的问题是,深拷贝通常需要灵活地处理不能进行简单自动化特殊情况(例如未受管理的资源)。
http://www.cnblogs.com/gengaixue/archive/2012/07/11/2586411.html
C#对象克隆介绍的更多相关文章
- Java提高篇——对象克隆(复制)
假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...
- Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
Java对象克隆(Clone)及Cloneable接口.Serializable接口的深入探讨 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的克隆,就不得不说为什么 ...
- (转)Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
原文地址:http://blog.csdn.net/kenthong/article/details/5758884 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的 ...
- Java对象克隆详解
原文:http://www.cnblogs.com/Qian123/p/5710533.html 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = appl ...
- js对象克隆, 深复制.
亲测有效: //对象克隆 function clone(obj) { // Handle the 3 simple types, and null or undefined if (null == o ...
- 数据传输对象(DTO)介绍及各类型实体比较
数据传输对象(DTO)介绍及各类型实体比较 本文将介绍DDD分层架构中广泛使用的数据传输对象Dto,并且与领域实体Entity,查询实体QueryObject,视图实体ViewModel等几种实体进行 ...
- DDD分层架构之值对象(介绍篇)
DDD分层架构之值对象(介绍篇) 前面介绍了DDD分层架构的实体,并完成了实体层超类型的开发,同时提供了验证方面的支持.本篇将介绍另一个重要的构造块——值对象,它是聚合中的主要成分. 如果说你已经在使 ...
- 【java】对象克隆protected Object clone() throws CloneNotSupportedException
package 对象克隆; class A implements Cloneable{//要具备clone()功能必须要实现Cloneable接口,此接口里无方法,只起标识作用. private St ...
- 从零开始学习前端JAVASCRIPT — 4、JavaScript基础Math和Date对象的介绍
Math对象的介绍 1:Math对象 Math 对象用于执行数学任务.并不像 Date 和 String 那样是对象的类,因此没有构造函数 Math().您无需创建它,通过把 Math 作为对象使用就 ...
随机推荐
- CMD的几个常用API
一: define, 全局函数,用来定义模块. 参数: 1.id 模块标识(可省略) 2.deps模块依赖(比如jquery)(可省略) 3.factory:可能是: (1)对象 (2)字符串 ①和 ...
- mysql批量替换单字段
update 表名 set 字段名 = replace(字段名,'被替换内容','要替换内容'); 指定有人查这个!!!
- @SuppressWarnings("finally")
@SuppressWarnings.该批注的作用是给编译器一条指令,告诉它对被批注的代码元素内部的某些警告保持静默. 批注允许您选择性地取消特定代码段(即,类或方法)中的警告.其中的想法是当您看到 ...
- C# 生成条形码图片,效果不错
//首先引用 条码库BarcodeLib.dll using System; using System.Collections.Generic; using System.Linq; using Sy ...
- Spring MVC之视图解析器和URL-Pattern的配置方案
上期讲解了第一入门案例之后接下来了解一下视图解析器与URL-Pattern的配置方案 先来说视图解析器,在上次博客文章中我们完成了入门案例,接下来我们就在上一个例子中完善一下体出视图解析器 <? ...
- 混合开发H5的图片怎么适配自己想要的大小
1.先上个自己没适配的图,这个图没显示全,因为用的是webview 所以 用的是webView的代理事件 解决 2.上代码 NSString *injectionJSString = @"v ...
- PHP乱码完美解决
文章来源 http://www.lupaworld.com/forum.php?mod=viewthread&tid=148807 A.首先说下HTML中文乱码问题的解决方法. 比如有个in ...
- 如何用js定义数组,用js来拼接json字段
定义js数组的方式有: var arr = (); var arr = []; var arr = new Array(); 如何拼接成一个json字段. <!DOCTYPE HTML PUBL ...
- check_env函数解析
又是一个比较长的函数,是用来检查文件权限,目录条件的.具体代码如下: check_env() { # Check user privilege. #检查用户权限 check_user root # C ...
- C++开发过程多线程同步lock的实现
在程序开发过程经常使用到多线程,而多线程始终与锁存在紧密地联系,以下详细的介绍如何在C++程序开发过程中自定义锁的几种方法. 1. 下面给出一段代码展现如何通过Mutex实现锁的功能(window p ...