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

所谓深浅复制可解读为:

  • 浅复制:在C#中调用Object类的 MemberwiseClone() 方法即为浅复制。如果字段是值类型的,则对字段执行逐位复制,如果字段是引用类型的,则复制对象的引用,而不复制对象,因此:原始对象和其副本引用同一个对象!
  • 深复制:如果字段是值类型的,则对字段执行逐位复制,如果字段是引用类型的,则把引用类型的对象指向一个全新的对象!

上述的解释可能看不太懂,我们作如下案例进行分析:

class Program
{
public static void Main()
{
//创建P1对象
Person p1 = new Person();
p1.Age = ;
p1.Name = "Sam";
p1.IdInfo = new IdInfo(""); //通过浅复制 得到P2对象
Person p2 = p1.ShallowCopy();
//分别输出
Console.WriteLine("对象P1相关属性如下");
DisplayValues(p1);
//p1.Name = "";
//p1.IdInfo.IdNumber = "XXXXX";
Console.WriteLine("对象P2相关属性如下");
DisplayValues(p2); //现在测试深复制
Person p3 = p1.DeepCopy(); p1.Name = "George";
p1.Age = ;
p1.IdInfo.IdNumber = "";
Console.WriteLine("对象P1相关属性如下");
DisplayValues(p1);
//p1.IdInfo.IdNumber = "CCCCCCC";
Console.WriteLine("对象P3相关属性如下");
DisplayValues(p3);
Console.Read();
} public static void DisplayValues(Person p)
{
Console.WriteLine(" Name: {0:s}, Age: {1:d}", p.Name, p.Age);
Console.WriteLine(" Value: {0:d}", p.IdInfo.IdNumber);
}
} public class IdInfo
{
public string IdNumber; public IdInfo(string IdNumber)
{
this.IdNumber = IdNumber;
}
} public class Person
{
public int Age;
public string Name;
public IdInfo IdInfo; public Person ShallowCopy()
{
return (Person)this.MemberwiseClone();
} public Person DeepCopy()
{
Person other = (Person)this.MemberwiseClone();
other.IdInfo = new IdInfo(IdInfo.IdNumber);
other.Name = String.Copy(Name);
return other;
}
}

上述代码分析如下:
原始对象P1,通过浅复制得到对象P2,通过深复制得到P3
原始对象P1中的值类型属性有:Age 和 Name ,引用类型对象有:IdInfo
根据上述浅复制的概念可知:P2中的Age 和 Name 相对于 P1是全新的,但P2中的 IdInfo 和 P1中的 IdInfo 是同一个对象,二者同在一个内存地址!
根据上述深复制的概念可知:P3中的Age 和 Name 相对于 P1是全新的,但P3中的 IdInfo 和 P1中的 IdInfo 不是同一个对象,也就是说 P3中的IdInfo是一个全新的对象,开辟了自己的内存地址!
上述代码测试如下:

我们现在讲代码修改如下:

public static void Main()
{
//创建P1对象
Person p1 = new Person();
p1.Age = ;
p1.Name = "Sam";
p1.IdInfo = new IdInfo(""); //通过浅复制 得到P2对象
Person p2 = p1.ShallowCopy();
//分别输出
Console.WriteLine("对象P1相关属性如下");
DisplayValues(p1);
p1.Name = "浅复制中,修改了P1的Name属性,但Name是值类型,所以不会影响P2";
p1.IdInfo.IdNumber = "浅复制中,修改了P1的IdInfo属性,但IdInfo是引用类型,所以会影响P2 (浅复制中引用类型原始对象和副本指向同一内存地址)";
Console.WriteLine("对象P2相关属性如下");
DisplayValues(p2); Console.Read();
}

在输出P2之前,我们修改了P1对象的值类型Name 和 引用类型 IdInfo 。
无论是浅复制还是深复制,副本中的值类型都是全新的!
浅复制中原始对象和副本的引用类型指向同一内存地址,所以,修改了P1的IdInfo会同时影响P2的IdInfo
输出如下:

继续修改代码,如下:

public static void Main()
{
//创建P1对象
Person p1 = new Person();
p1.Age = ;
p1.Name = "Sam";
p1.IdInfo = new IdInfo(""); //现在测试深复制
Person p3 = p1.DeepCopy(); p1.Name = "George";
p1.Age = ;
p1.IdInfo.IdNumber = "";
Console.WriteLine("对象P1相关属性如下");
DisplayValues(p1);
p1.IdInfo.IdNumber = "深复制中,修改了P1的IdInfo属性,即使IdInfo是引用类型,也不会影响P3 (深复制中引用类型原始对象和副本分别指向不同的内存地址)";
Console.WriteLine("对象P3相关属性如下");
DisplayValues(p3);
Console.Read();
}

深复制中原始对象和副本的引用类型指向各自的地址,两者完全是两个不同的对象!
因此:修改P1不会影响P3
so,是不是很简单,是不是很Easy.
深浅复制主要用于当创建一个对象需要消耗过多资源时,可以采取复制的方法提升效率!
大话设计模式的原话是这样滴:当你New一个对象时,每New一次,都需要执行一个构造函数,如果构造函数的执行时间很长,那么多次New对象时会大大拉低程序执行效率,因此:一般在初始化信息不发生变化的前提下克隆是最好的办法,这既隐藏了对象的创建细节,又大大提升了性能
当然,如果每个类都要写自己的深复制,这岂不是非常非常麻烦,因此,有一个通用的深复制方法,如下:

/// <summary>
/// 通用的深复制方法
/// </summary>
/// <typeparam name="T"></typeparam>
[Serializable]
public class BaseClone<T>
{
public virtual T Clone()
{
using (MemoryStream memoryStream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, this);
memoryStream.Position = ;
return (T)formatter.Deserialize(memoryStream);
}
}
}

相关案例如下(通用的深复制方法使用时必须为相关类及类的引用类型加上可序列化标识:[Serializable]):

class Program
{
public static void Main()
{
//创建P1对象
Person p1 = new Person();
p1.Age = ;
p1.Name = "Sam";
p1.IdInfo = new IdInfo(""); //现在测试深复制
Person p3 = p1.Clone(); p1.Name = "George";
p1.Age = ;
p1.IdInfo.IdNumber = "";
Console.WriteLine("对象P1相关属性如下");
DisplayValues(p1);
p1.IdInfo.IdNumber = "深复制中,修改了P1的IdInfo属性,即使IdInfo是引用类型,也不会影响P3 (深复制中引用类型原始对象和副本分别指向不同的内存地址)";
Console.WriteLine("对象P3相关属性如下");
DisplayValues(p3);
Console.Read();
} public static void DisplayValues(Person p)
{
Console.WriteLine(" Name: {0:s}, Age: {1:d}", p.Name, p.Age);
Console.WriteLine(" Value: {0:d}", p.IdInfo.IdNumber);
} } [Serializable]
public class IdInfo
{
public string IdNumber; public IdInfo(string IdNumber)
{
this.IdNumber = IdNumber;
}
} [Serializable]
public class Person : BaseClone<Person>
{
public int Age;
public string Name; public IdInfo IdInfo; public Person ShallowCopy()
{
return (Person)this.MemberwiseClone();
} public Person DeepCopy()
{
Person other = (Person)this.MemberwiseClone();
other.IdInfo = new IdInfo(IdInfo.IdNumber);
other.Name = String.Copy(Name);
return other;
} public override Person Clone()
{
using (MemoryStream memoryStream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, this);
memoryStream.Position = ;
return (Person)formatter.Deserialize(memoryStream);
}
}
} /// <summary>
/// 通用的深复制方法
/// </summary>
/// <typeparam name="T"></typeparam>
[Serializable]
public class BaseClone<T>
{
public virtual T Clone()
{
using (MemoryStream memoryStream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, this);
memoryStream.Position = ;
return (T)formatter.Deserialize(memoryStream);
}
}
}

原文链接

C# 深浅复制 MemberwiseClone(转载)的更多相关文章

  1. C#设计模式(6)——原型模式(Prototype Pattern) C# 深浅复制 MemberwiseClone

    C#设计模式(6)——原型模式(Prototype Pattern)   一.引言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创 ...

  2. C# Json反序列化 C# 实现表单的自动化测试<通过程序控制一个网页> 验证码处理类:UnCodebase.cs + BauDuAi 读取验证码的值(并非好的解决方案) 大话设计模式:原型模式 C# 深浅复制 MemberwiseClone

    C# Json反序列化   Json反序列化有两种方式[本人],一种是生成实体的,方便处理大量数据,复杂度稍高,一种是用匿名类写,方便读取数据,较为简单. 使用了Newtonsoft.Json,可以自 ...

  3. C# 深浅复制 MemberwiseClone

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

  4. 详谈OC(object-c)深浅复制/拷贝-什么情况下用retain和copy

    读前小提示:对于深浅复制有一个清楚的了解,对于学习oc的朋友来说,至关重要.那么首先,我们要明白深浅复制是如何定义的呢.这里为了便于朋友们理解,定义如下. 浅 复 制:在复制操作时,对于被复制的对象的 ...

  5. OC-深浅复制

    [OC学习-26]对象的浅拷贝和深拷贝——关键在于属性是否可被拷贝 对象的拷贝分为浅拷贝和深拷贝, 浅拷贝就是只拷贝对象,但是属性不拷贝,拷贝出来的对象和原来的对象共用属性,即指向同一个属性地址. 深 ...

  6. Objective-c 深浅复制

    深浅复制的定义: 浅复制:在复制时,对于被复制对象的每一层都是指针复制. 深复制:在复制时,对于被复制的对象至少有一层是对象复制. 完全复制:在复制时,对于被复制对象的每一层都是完全复制. retai ...

  7. Python基础之列表深浅复制和列表推导式

    一.列表深浅复制: 浅拷贝内存图如下: 深拷贝内存图如下: 二.列表推导式: 实例: """ 列表推导式 练习:exercise01 """ ...

  8. 潭州课堂25班:Ph201805201 第五课:格式化输出和深浅复制 (课堂笔记)

    格式化输出和字符串转义 占位符 使用示意 作用 %s '%s %s' % ('hello', 'world') 表示占位的是str %d '%d %d' % (1, 2) 表示占位的是int %d ' ...

  9. 【Python初级】由判定回文数想到的,关于深浅复制,以及字符串反转的问题

    尝试用Python实现可以说是一个很经典的问题,判断回文数. 让我们再来看看回文数是怎么定义的: 回数是指从左向右读和从右向左读都是一样的数,例如1,121,909,666等 解决这个问题的思路,可以 ...

随机推荐

  1. Linux 学习笔记之超详细基础linux命令 Part 12

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 11---------------- ...

  2. Python:BeautifulSoup移除某些不需要的属性

    很久之前,我看到一个问题,大概是: 他爬了一段html,他获取下了所需的部分(img标签部分),但是不想保留img标签的某些属性, 比如 <img width="147" h ...

  3. python 定时修改数据库

    当需要定时修改数据库时,一般我们都选择起一个定时进程去改库.如果将这种定时任务写入业务中,写成一个接口呢,定时进程显得有些不太合适?如果需要定时修改100次数据库,常规做法会启动100个进程,虽然这种 ...

  4. 测试中Android与IOS分别关注的点

    主要从本身系统的不同点.系统造成的不同点.和注意的测试点做总结 1.自身不同点 研发商:Adroid是google公司做的手机系统,IOS是苹果公司做的手机系统 开源程度:Android是开源的,IO ...

  5. VS发布web应用程序报:无法识别的特性“xmlns:xdt”。请注意特性名称区分大小写 或 未能将文件obj\...复制到obj\...未能找到路径

    问题1:无法识别的特性“xmlns:xdt”.请注意特性名称区分大小写 问题2:未能将文件obj\...复制到obj\...未能找到路径 解决办法:将web项目文件下的obj文件夹从项目中排除,然后再 ...

  6. Opengl正交矩阵 glOrthof 数学原理(转)

    http://blog.sina.com.cn/s/blog_6084f588010192ug.html 在opengles1.1中设置正交矩阵只要一个函数调用就可以了:glOrthof,但是open ...

  7. 15LaTeX学习系列之---LaTeX里插入数学公式

    目录 目录 前言 (一)常用的数学公式命令 ==1.上下标== ==2.矢量== ==3.括号== ==4.符号关系== ==5.三角形符号== ==6.求和与累积== ==7.积分与微分== ==8 ...

  8. layui框架学习记录

    自定义layui动态渲染的数据表格单元格样式 layui.use('table', function() { var table = layui.table; table.render({ elem: ...

  9. javascript中获取元素尺寸

    Javascript获取获取屏幕.浏览器窗口 ,浏览器,网页高度.宽度的大小 屏幕可用工作区宽度:window.screen.availHeight,和浏览器无关,屏幕相关屏幕可用工作区高度:wind ...

  10. Frameworks(不定时更新)

    iOS8.4 Frameworks 更新时间:2015年8月17日 Accelerate iOS4.0引入了Accelerate框架,该框架的接口可用于执行数学.大数字以及DSP运算.和开发者个人编写 ...