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

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

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

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary; namespace CloneDemo
{
[Serializable]
class DemoClass
{
public int i = ;
public int[] iArr = { , , }; 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 = ;
return formatter.Deserialize(stream) as DemoClass;
}
} class Program
{
static void Main(string[] args)
{
DemoClass a = new DemoClass();
a.i = ;
a.iArr = new int[] { , , };
DemoClass b = a.Clone1();
DemoClass c = a.Clone2(); // 更改 a 对象的iArr[0], 导致 b 对象的iArr[0] 也发生了变化 而 c不会变化
a.iArr[] = ; 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 = {,,}; 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[] = ; 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 = {,,}; // 默认构造函数
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[] = ; 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(, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
}

C#之MemberwiseClone与Clone的更多相关文章

  1. 类复制 MemberwiseClone与Clone(深 浅 Clone)

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

  2. PrototypePattern(原型模式)-----Java/.Net

    原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.

  3. 一眼看懂深浅拷贝(clone)-C#

    这是使用的是序列化的方式实现深拷贝 [Serializable] class Person:ICloneable { /// <summary> /// 字符串在clone 中类似于值类型 ...

  4. MemberwiseClone和DeepClone

    文章转自:http://www.cnblogs.com/zhangji/archive/2011/02/23/1961897.html MemberwiseClone 方法创建一个浅表副本,具体来说就 ...

  5. Prototype:Copy和Clone

    原型模式在C#中的实现比较直接,因为只需要继承了IClone的接口,就可以通过重写Clone方法,调用MemberwiseClone()来实现ProtoType的方式. class Test:IClo ...

  6. win10 uwp clone

    clone 可以用MemberwiseClone来复制一个类 但这个复制是浅复制,创建一个新的object然后复制值字段,对于引用就直接复制引用,不复制引用的本身,指向同样引用 如果要复制引用,可以使 ...

  7. C# 深浅复制 MemberwiseClone(转载)

    最近拜读了大话设计模式:原型模式,该模式主要应用C# 深浅复制来实现的!关于深浅复制大家可参考MSDN:https://docs.microsoft.com/zh-cn/dotnet/api/syst ...

  8. C# 深浅复制 MemberwiseClone

    学无止境,精益求精 十年河东,十年河西,莫欺少年穷 学历代表你的过去,能力代表你的现在,学习代表你的将来 最近拜读了大话设计模式:原型模式,该模式主要应用C# 深浅复制来实现的!关于深浅复制大家可参考 ...

  9. Object.MemberwiseClone

    [Object.MemberwiseClone] Creates a shallow copy of the current Object. protected object MemberwiseCl ...

随机推荐

  1. 12个常用的js正则表达式

    在这篇文章里,我已经编写了12个超有用的正则表达式,这可是WEB开发人员的最爱哦. 1.在input框中只能输入金额,其实就是只能输入最多有两位小数的数字 //第一种在input输入框限制 <i ...

  2. 机器学习公开课笔记(3):Logistic回归

    Logistic 回归 通常是二元分类器(也可以用于多元分类),例如以下的分类问题 Email: spam / not spam Tumor: Malignant / benign 假设 (Hypot ...

  3. 小白科普之JavaScript的数组

    一.与其他语言数据的比较    相同点:有序列表    不同点:js的数组的每一项可以保存任何类型的数据:数组的大小是可以动态调整的 二.数组创建的两种方法 1)  var colors = new ...

  4. Slider插件(滑动条,拉链)

    Slider插件(滑动条,拉链) 下载地址:http://files.cnblogs.com/elves/Slider.rar 提示:微软AJAX插件中也带此效果!

  5. 代码规范和常用的js插件以及测试工具

    1.代码规范 .model层 1.1.1database file_proerty 1.1.2java fileProperty. 1.2.字段要有空指针 1.3.不创建爱数据库外键约束 1.4.已知 ...

  6. 修改Capfile,在正式环境不再使用migration修改数据库

    原因是这样的,运维不开放正式环境数据库的alter权限,所以每次都要给他们把sql语句发过去, 由他们来操作. https://github.com/capistrano/rails Require ...

  7. ZeroMQ(java)中对IO的封装(StreamEngine)

    哎,各种各样杂七杂八的事情...好久没有看代码了,其实要搞明白一个与IO相关的框架,最好的办法就是把它的I/0的读写两个过程搞清楚...例如在netty中,如果能将eventLoop的运行原理搞清楚, ...

  8. HDOJ 1026 dfs路径保存

    #include<cstdio> #include<cstring> #include<cmath> ][]; #define inf 0xffffff int n ...

  9. ZJOI Day 2 游记

    ---恢复内容开始--- 去ZJOI Day 2打了一会酱油...各种神犇大爷都来屠,南外的小朋友也来屠我们了真是感动...没有看到毛爷爷真是可惜.. Day[-1] 早上还在上课,吃完中饭立马跑去找 ...

  10. 【Python】python list 迭代删除

    最好方式使用filter,代码示例: def _filter(self, item): ): return False return True #lambda e:e%!= data['items'] ...