当前位置: 首页 > news >正文

C#对象克隆介绍 (转)

浅拷贝和深拷贝

有两种对象克隆的方法:浅拷贝和深拷贝。浅拷贝只是复制引用,而不会复制引用的对象。深拷贝会复制引用的对象。

因此,原始对象中的引用和浅拷贝对象中的同一个引用都指向同一个对象。而深拷贝的对象包含了对象的一切直接或间接的引用。参看维基百科(http://en.wikipedia.org/wiki/Object_copy)来获得更多解释。

ICloneable接口

ICloneable接口包含一个Clone方法,可以用来创建当前对象的拷贝。


   
public interface ICloneable
{
object Clone();
}


ICloneable的问题是Clone方法并不会显式地指定是执行浅拷贝或深拷贝,因此调用者将无法确定实际情况。因此,有一些关于把ICloneable从.NET框架中淘汰的讨论。MSDN文档似乎暗示Clone方法是进行的深拷贝,但是文档没有明确的说明:

ICloneable接口包含一个成员方法,Clone,意在支持超过MemberWiseClone所提供的功能... MemberWiseClone进行的是浅拷贝...

类型安全的克隆

ICloneable的另一个缺点是Clone方法返回的是一个对象,因此每次调用Clone都要进行一次强制类型转换。


   
Person joe = new Person();
joe.Name
= " Joe Smith " ;
Person joeClone
= (Person)joe.Clone();


一种可以避免进行强制类型转换的方式是提供你自己的类型安全的Clone方法。注意,你依然要提供ICloneable.Clone方法的以满足iCloneable接口的要求。


   
public class Person : ICloneable
{
public string Name;
object ICloneable.Clone()
{
return this .Clone();
}
public Person Clone()
{
return (Person) this .MemberwiseClone();
}
}

选择克隆方法

1. 手工克隆

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


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

相关文章:

  • 使用tpcc-mysql进行性能测试
  • Struts action的单例与多例
  • windows下实现屏幕分享(C#)
  • Urxvt最简配置
  • 解决SecureCRT连接linux终端中文显示乱码
  • 无需重启,让组策略立即生效
  • 接触GitHub的第一次
  • android学习总结(20120721)
  • Java设计模式之依赖倒置原则
  • linux创建逻辑卷(lv)并挂载
  • C语言加密文本
  • [PHP] 代码重用与函数
  • Error处理: “非法字符: \65279”的解决办法
  • 使用vue构建一个自动建站项目
  • 各种内存分配器的对比测试
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • ES6系统学习----从Apollo Client看解构赋值
  • ES学习笔记(12)--Symbol
  • Material Design
  • rabbitmq延迟消息示例
  • rc-form之最单纯情况
  • spring security oauth2 password授权模式
  • Swift 中的尾递归和蹦床
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 干货 | 以太坊Mist负责人教你建立无服务器应用
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • 微服务核心架构梳理
  • 我的业余项目总结
  • k8s使用glusterfs实现动态持久化存储
  • Semaphore
  • 如何用纯 CSS 创作一个货车 loader
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​VRRP 虚拟路由冗余协议(华为)
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • ​人工智能书单(数学基础篇)
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (转)memcache、redis缓存
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • .Net mvc总结
  • .net(C#)中String.Format如何使用
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .NET企业级应用架构设计系列之技术选型
  • .NET中使用Redis (二)
  • .set 数据导入matlab,设置变量导入选项 - MATLAB setvaropts - MathWorks 中国
  • /deep/和 >>>以及 ::v-deep 三者的区别
  • @media screen 针对不同移动设备
  • [ Linux ] Linux信号概述 信号的产生
  • [Android]竖直滑动选择器WheelView的实现
  • [C++]C++类基本语法
  • [Go WebSocket] 多房间的聊天室(五)用多个小锁代替大锁,提高效率
  • [HITCON 2017]SSRFme perl语言的 GET open file 造成rce
  • [JS入门到进阶] 7条关于 async await 的使用口诀,新学 async await?背10遍,以后要考!快收藏