MemberwiseClone 方法创建一个浅表副本,具体来说就是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。
如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。

为了实现深度复制,我们就必须遍历有相互引用的对象构成的图,并需要处理其中的循环引用结构。这无疑是十分复杂的。幸好借助.Net的序列化和反序 列化机制,可以十分简单的深度Clone一个对象。原理很简单,首先将对象序列化到内存流中,此时对象和对象引用的所用对象的状态都被保存到内存 中。.Net的序列化机制会自动处理循环引用的情况。然后将内存流中的状态信息反序列化到一个新的对象中。这样一个对象的深度复制就完成了。在原型设计模 式中CLONE技术非常关键。

下面的代码就是演示这个问题:

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary; namespace CloneDemo
{
[Serializable]
class DemoClass
{
public int i = 0;
public int[] iArr = { 1, 2, 3 }; public DemoClass Clone1() //浅CLONE
{
return this.MemberwiseClone() as DemoClass;
} public DemoClass Clone2() //深clone
{
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0;
return formatter.Deserialize(stream) as DemoClass;
}
} class Program
{
static void Main(string[] args)
{
DemoClass a = new DemoClass();
a.i = 10;
a.iArr = new int[] { 8, 9, 10 };
DemoClass b = a.Clone1();
DemoClass c = a.Clone2(); // 更改 a 对象的iArr[0], 导致 b 对象的iArr[0] 也发生了变化 而 c不会变化
a.iArr[0] = 88; Console.WriteLine("MemberwiseClone");
Console.WriteLine(b.i);
foreach (var item in b.iArr)
{
Console.WriteLine(item);
} Console.WriteLine("Clone2");
Console.WriteLine(c.i);
foreach (var item in c.iArr)
{
Console.WriteLine(item);
} Console.ReadLine();
}
}
}

另外一个例子是针对数组,C#中的数组是引用型的变量,我们通过数组来进行演示: 
浅拷贝

using System;

class ShallowCopy : ICloneable
{
public int[] v = {1,2,3}; public Object Clone()
{
return this.MemberwiseClone();
} public void Display()
{
foreach(int i in v)
Console.Write( i + ", ");
Console.WriteLine();
}
} class Client
{
public static void Main()
{ ShallowCopy sc1 = new ShallowCopy();
ShallowCopy sc2 = (ShallowCopy)sc1.Clone();
sc1.v[0] = 9; sc1.Display();
sc2.Display(); }
}

ShallowCopy对象实现了一个浅拷贝,因此当对sc1进行克隆时,其字段v并没有克隆,这导致sc1与sc2的字段v都指向了同一个v,因此,当修改了sc1的v[0]后,sc2的v[0]也发生了变化。

深拷贝:

using System;

class DeepCopy : ICloneable
{
public int[] v = {1,2,3}; // 默认构造函数
public DeepCopy()
{
} // 供Clone方法调用的私有构造函数
private DeepCopy(int[] v)
{
this.v = (int[])v.Clone();
} public Object Clone()
{
// 构造一个新的DeepCopy对象,构造参数为
// 原有对象中使用的 v
return new DeepCopy(this.v);
} public void Display()
{
foreach(int i in v)
Console.Write( i + ", ");
Console.WriteLine(); }
} class Client
{
public static void Main()
{
DeepCopy dc1 = new DeepCopy();
DeepCopy dc2 = (DeepCopy)dc1.Clone();
dc1.v[0] = 9; dc1.Display();
dc2.Display(); }
}

这次在克隆的时候,不但克隆对象本身,连里面的数组字段一并克隆。因此,最终打印出来的dc1与dc2不同。

当然我们也可以建个深拷贝的帮助类:

public static class ObjectCopier
{ /// <summary>
/// Perform a deep Copy of the object.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T Clone<T>(T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
} // Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
} IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
} }
转自:https://www.cnblogs.com/MRRAOBX/articles/4084171.html

最新文章

  1. jQuery.template.js 简单使用
  2. EntityFramework中几种更改数据的方式
  3. stoneniqiu 理想就是自己喜欢做,并对社会和他人都有意义的事情!
  4. CRM 2013 系统设置新功能一:界面自动保存 及 SDK 中 Xrm.Page.data.entity.save
  5. 在Xcode6.1.1模拟器中点击UITextView不出现软键盘?
  6. Linux加载DTS设备节点的过程(以高通8974平台为例)
  7. http请求利器: 今天配置出了RESTClient,用MAVEN构建了UI运行包
  8. swift3.0 coredata 的使用
  9. HttpClient 建立http连接,https连接,传输数据文件
  10. Java基础知识强化之集合框架笔记40:Set集合之HashSet存储自定义对象并遍历
  11. elasticsearch系列(四)部署
  12. 一些JQuery使用技巧
  13. 剑指offer 7. 递归和循环 斐波那契数列
  14. 有关于并发中的死锁(Deadlock)、饥饿(Starvation)、活锁(Livelock)
  15. 震惊!!!python可以用中文来写代码
  16. 唯美PS转手绘之SAI篇_百度经验
  17. [UE4]Safe Zone:安全区域
  18. Linux下Mysql安装(RPM安装)
  19. Office Web Apps 错误日志
  20. 第3章 文件I/O(6)_高级文件操作:文件锁

热门文章

  1. 【VS开发】VS2010中导入ActiveX控件
  2. [转帖]calico网络原理及与flannel对比
  3. Oracle导入/导出某个用户下的数据库
  4. vue配置外放generate-asset-webpack-plugin
  5. Vanya and Scales CodeForces - 552C (思维)
  6. url协议+域名+端口号
  7. .net get set用法
  8. 【题解】P3391 文艺平衡树
  9. C++内存分配和分区
  10. O039、Unshelve Instance 操作详解