C#克隆
克隆方法是原型设计模式中必须使用的方式,它将返回一个与当前对象数据一致的对象。正如其名,犹如一个模子雕刻而出。克隆类型分为两种:浅克隆、深克隆。
1、浅克隆
浅克隆方式是最简单、最直接的方式。只需要类实现接口ICloneable(在命名空间System.Runtime.InteropServices下)的Clone方法,在方法中使用加入对当前类的MemberwiseClone()方法即可。在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象。

如:
public class Student:ICloneable
{
/// <summary>
/// 值类型
/// </summary>
public int ID { get; set; }
/// <summary>
/// 引用类型
/// </summary>
public object obj { get; set; } public object Clone()
{
return this.MemberwiseClone();
}
}
以上方法实现了对类对象的浅克隆方式。但是在该类中具有引用类型字段,浅克隆方法无法对引用字段进行克隆,引用字段仅仅是对其进行了地址引用。所以,当修改原本或者副本的引用字段的数据时,另一个对象的引用对象的数据同样会变化。深克隆将有效的解决此问题。
2、深克隆
深克隆相对于浅克隆方式比较复杂。深克隆是无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。

深克隆实现的机制是将对象进行序列化为数据后,再次将数据反序列化为新的对象。序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。注意,在实现序列化前需要在类的上方标记为可序列化。本文采用的序列化方式为二进制序列化。
主要实现的代码如下:
[Serializable]//标记特性:可序列化
public class Student
{
/// <summary>
/// 值类型
/// </summary>
public int ID { get; set; }
/// <summary>
/// 引用类型
/// </summary>
public object obj { get; set; } public Student Clone( )
{
Student clone = new Student();
using (Stream stream = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(stream, this);
stream.Seek(, SeekOrigin.Begin);
clone = formatter.Deserialize(stream) as Student;
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
}
return clone;
}
}
深克隆实现机制相对复杂、效率稍慢,但它克服了浅克隆方式的不足,使得克隆对象时将类中的引用类型数据完全克隆为新的对象,而不是引用原本中的对象。如此,在修改双方的引用类型对象的数据时不会对另一方造成干扰。
但为每一个类都实现克隆方式,而重复书写相同代码未免麻烦。因此引入泛型方法。
3、泛型方法实现克隆
泛型的出现使得可以良好的解决在多个类或结构体中都需要进行克隆时重复编写代码的麻烦。在外部只需要使用相关方法即可。其代码如下:
public class Clone
{
/// <summary>
/// 深克隆
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public static T DepthClone<T>(T t)
{
T clone = default(T);
using (Stream stream = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(stream, t);
stream.Seek(, SeekOrigin.Begin);
clone = (T)formatter.Deserialize(stream);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
}
return clone;
}
}
在外部使用的方法如下:
Student stu1 = new Student();//实例化一个对象
stu1.obj = new object();//实例化对象中的引用对象
Student stu2 = Clone.DepthClone(stu1);//深克隆对象
4、扩展方法
扩展方法的出现可以很好的解决类自身直接调用克隆方法,而不需要调用静态类的方法,返回对象值。但其本身与泛型方法类似,不过为了使所有类都能使用定义的深克隆方法,此处使用对顶级类Object进行方法的扩展,其返回的值也是object类型。具体方法如下:
/// <summary>
/// 注:扩展方法必须在静态类中
/// </summary>
public static class Clone
{
/// <summary>
/// 深克隆
/// </summary>
/// <param name="obj">原始版本对象</param>
/// <returns>深克隆后的对象</returns>
public static object DepthClone(this object obj)
{
object clone = new object();
using (Stream stream = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(stream, obj);
stream.Seek(, SeekOrigin.Begin);
clone = formatter.Deserialize(stream);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
}
return clone;
}
}
使用方法示例:
Student stu1 = new Student();//实例化一个对象
stu1.obj = new object();//实例化对象中的引用对象
Student stu2 = stu1.DepthClone() as Student;//深克隆对象;注意:在此需要将object对象转换为我们需要的对象类型
C#克隆的更多相关文章
- SQL Server2014 SP2新增的数据库克隆功能
		
SQL Server2014 SP2新增的数据库克隆功能 创建测试库 --创建测试数据库 create database testtest use testtest go --创建表 )) --插入数 ...
 - GitHub实战系列~4.把github里面的库克隆到指定目录+日常使用  2015-12-11
		
GitHub实战系列汇总:http://www.cnblogs.com/dunitian/p/5038719.html ———————————————————————————————————————— ...
 - [转]Oracle 12c多租户特性详解:PDB 的创建、克隆与维护
		
转自:http://chuansong.me/n/443660447865 PDB 的创建和访问 在使用 dbca 建库时,创建数据库之前,可以保存一下创建脚本,分析其具体执行过程.以自定义方式创建名 ...
 - 克隆虚机网卡出现 Device eth0 does not seem to be present, delaying initialization 错误
		
错误原因 克隆的Linux系统在新的机器上运行,新服务器网卡物理地址已经改变.而/etc/udev/rules.d/70-persistent-net.rules这个文件确定了网卡和MAC地址的 ...
 - git用法之常用命令[克隆、提交]
		
1.克隆/下载项目 1)git clone git@git.soydai.cn:liuxuewen/static-file-3.0.git 或者 2)git clone http://git.soyd ...
 - Power服务器中KVM克隆新虚拟机
		
查看当前所有虚拟机:virsh list --all 克隆新虚拟机:virt-clone -o guest01 -n guest02 -f /var/lib/libvirt/images/guest ...
 - git学习(五):克隆和推送远程仓库
		
这里我已经注册好了GitHub账号了 生成本地的ssh和在github上添加ssh 在本地 ssh-keygen -t rsa -C "carryhjr@gmail.com" 一路 ...
 - Linux  VMware 克隆后无法启动eth0网卡
		
引: VMware 下LINUX出现:Device eth0 does not seem to be present, delaying initialization.解决办法 VMWare 克隆 复 ...
 - VMWare vSphere Client 克隆虚拟机 更改IP
		
克隆虚拟机后,查看该虚拟机所分配的MAC地址. 打开控制台,进入linux界面. 打开/etc/udev/rules.d/70-persistent-net.rules内容如下面例子所示: # vi ...
 - DOM 节点的克隆与删除
		
无奈的开头 关于DOM节点操作,如果仅仅是根据标准API来操作,那是最简单不过的了.但是现实中却哪有这么容易的问题让我们解决,其实不仅仅是节点的克隆与删除,节点的添加也是如此,而且添加节点需要考虑的情 ...
 
随机推荐
- 条款2:尽量以const, enum, inline替换#define
			
原因: 1. 追踪困难,由于在编译期已经替换,在记号表中没有. 2. 由于编译期多处替换,可能导致目标代码体积稍大. 3. define没有作用域,如在类中定义一个常量不行. 做法: 可以用const ...
 - PyQt5信号与槽
			
简单使用 可以使用designer的一个模式定义,也可以自己定义,在__init__函数里,self.btn.clicked.connect(self.text.clear). 注意:槽不用加括号,可 ...
 - 二叉树查找树中序后继 · Inorder Successor in Binary Search Tree
			
[抄题]: 给一个二叉查找树以及一个节点,求该节点的中序遍历后继,如果没有返回null [思维问题]: 不知道分合算法和后序节点有什么关系:直接return表达式就行了,它自己会终止的. [一句话思路 ...
 - IBM MQ 与spring的整合
			
文件名:applicationContext-biz-mq.xml 新浪博客把里面的代码全部转换成HTML了,所以无法粘贴 可以查看CSDN里面的:http://blog.csdn.net/xiazo ...
 - Loadrunner12.5-录制http://www.gw.com.cn/网页时提示“SSL身份验证失败”错误,这是为什么呢?
			
问题:LR产品,录制http://www.gw.com.cn/ 网页时提示下图错误,这是为什么呢? 请在如下recording options中选择正确的SSL版本,再进行录制. 注:如何确定那个SS ...
 - advance shading——菲涅耳现象
			
(计算光照的时候,从两点出发考虑,光的传播方向,以及光的在这个方向上的能量.) 光与表面交互的模型包含两类:和物体表面(surface)以及和物体的内部(body).而subsurface指的是在物体 ...
 - spring mvc MultipartFile 上传文件 当文件较小时(10k) ,无法上传成功 。
			
<!-- SpringMVC上传文件时,需要配置MultipartResolver处理器 --> <bean id="multipartResolver" cla ...
 - EnrichPipeline文档
			
https://sourceforge.net/projects/enrichmentpipeline/
 - Silverlight StoryBoard 动态切换ImageSource
			
Silverlight StoryBoard 动态切换ImageSource <StackPanel Grid.Row="1" Orientation="Horiz ...
 - 2018.08.06 bzoj1500: [NOI2005]维修数列(非旋treap)
			
传送门 平衡树好题. 我仍然是用的fhqtreap,感觉速度还行. 维护也比线段树splay什么的写起来简单. %%%非旋treap大法好. 代码: #include<bits/stdc++.h ...