C# 复制(深拷贝、浅拷贝)
Object.MemberwiseClone 方法
创建当前 Object 的浅表副本。
protected Object MemberwiseClone()
MemberwiseClone 方法创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。 如果字段是值类型的,则对该字段执行逐位复制。 如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。
例如,考虑对象X引用对象 A 和 B , 对象 B 依次引用对象 C。 X 的浅表副本创建一个新对象 X2,该对象也引用对象 A 和 B。 相比而言,X 的深层副本创建一个新对象 X2,该对象引用新对象 A2 和 B2(分别为 A 和 B 的副本)。 B2 又引用新对象 C2,C2 是 C 的副本。 该示例阐释了浅层和深层复制操作之间的区别。

有很多方法可以实现深层复制操作,前提是浅表复制操作由 MemberwiseClone 方法执行但不符合您的需求。
这些要求包括:
- 调用要复制的对象的类构造函数以创建含有从第一个对象中提出的属性值的第二个对象。 这假定对象的值完全由类构造函数定义。
- 调用 MemberwiseClone 方法创建的对象的浅表副本,然后将指定新的对象,其值均相同,原始对象的任何属性或字段的值是引用类型。 该示例中的 DeepCopy 方法阐释了这种方法。
- 序列化要深层复制的对象,然后将序列化的数据还原到另一个对象变量。
- 使用带递归的反射执行的深层复制操作。
下面的示例演示 MemberwiseClone 方法。 它定义了 ShallowCopy 方法,该方法通过调用 MemberwiseClone 方法来在 Person 对象上执行浅表复制操作。 它还定义了在 Person 对象上执行深层复制操作的DeepCopy 方法。
using System; public class IdInfo
{
public int IdNumber; public IdInfo(int 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(this.IdInfo.IdNumber);
return other;
}
} public class Example
{
public static void Main()
{
// Create an instance of Person and assign values to its fields.
Person p1 = new Person();
p1.Age = 42;
p1.Name = "Sam";
p1.IdInfo = new IdInfo(6565); // Perform a shallow copy of p1 and assign it to p2.
Person p2 = (Person) p1.ShallowCopy(); // Display values of p1, p2
Console.WriteLine("Original values of p1 and p2:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p2 instance values:");
DisplayValues(p2); // Change the value of p1 properties and display the values of p1 and p2.
p1.Age = 32;
p1.Name = "Frank";
p1.IdInfo.IdNumber = 7878;
Console.WriteLine("\nValues of p1 and p2 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p2 instance values:");
DisplayValues(p2); // Make a deep copy of p1 and assign it to p3.
Person p3 = p1.DeepCopy();
// Change the members of the p1 class to new values to show the deep copy.
p1.Name = "George";
p1.Age = 39;
p1.IdInfo.IdNumber = 8641;
Console.WriteLine("\nValues of p1 and p3 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p3 instance values:");
DisplayValues(p3);
} 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);
}
}
// The example displays the following output:
// Original values of p1 and p2:
// p1 instance values:
// Name: Sam, Age: 42
// Value: 6565
// p2 instance values:
// Name: Sam, Age: 42
// Value: 6565
//
// Values of p1 and p2 after changes to p1:
// p1 instance values:
// Name: Frank, Age: 32
// Value: 7878
// p2 instance values:
// Name: Sam, Age: 42
// Value: 7878
//
// Values of p1 and p3 after changes to p1:
// p1 instance values:
// Name: George, Age: 39
// Value: 8641
// p3 instance values:
// Name: Frank, Age: 32
// Value: 7878
为了实现深度复制,我们就必须遍历有相互引用的对象构成的图,并需要处理其中的循环引用结构。这无疑是十分复杂的。幸好借助.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();
}
}
}
引用:http://www.cnblogs.com/zhangji/archive/2011/02/23/1961897.html
C# 复制(深拷贝、浅拷贝)的更多相关文章
- Java中的深拷贝(深复制)和浅拷贝(浅复制)
深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java.虽然java自动管理对象的回收,但对于深拷贝(深复 ...
- c# 内存的具体表现- 通用类型系统 深拷贝 浅拷贝 函数传参
c# 通用类型系统 及变量在 深拷贝 浅拷贝 函数传参 中的深层次的表现 在编程中遇到了一些想不到的异常,跟踪发现,自己对于c#变量在内存上的表现理解有偏差,系统的学习并通过代码实验梳理了各种情况下, ...
- python集合增删改查,深拷贝浅拷贝
集合 集合是无序的,不重复的数据集合,它里面的元素是可哈希的(不可变类型),但是集合本身是不可哈希(所以集合做不了字典的键)的.以下是集合最重要的两点: 去重,把一个列表变成集合,就自动去重了. 关系 ...
- JavaScript之深拷贝&浅拷贝
深拷贝&浅拷贝,说起来都明白,但是说不出所以然.今天就系统的整理下思绪,一点点的将其分析出所以然 废话不多说 浅拷贝 简单的说就是一个值引用,学生时代接触过编程的人都应该了解过指针,浅拷贝可以 ...
- 【opencv】imread 赋值 深拷贝浅拷贝
import cv2 import copy import os def filter_srcimg(dstimg): ss=3 srcimg=copy.deepcopy(dstimg) #aa=5 ...
- Java基础 深拷贝浅拷贝
Java基础 深拷贝浅拷贝 非基本数据类型 需要new新空间 class Student implements Cloneable{ private int id; private String na ...
- 【04】Python 深拷贝浅拷贝 函数 递归 集合
1 深拷贝浅拷贝 1.1 a==b与a is b的区别 a == b 比较两个对象的内容是否相等(可以是不同内存空间) a is b 比较a与b是否指向同一个内存地址,也就是a与b的id是否相 ...
- JS Object Deep Copy & 深拷贝 & 浅拷贝
JS Object Deep Copy & 深拷贝 & 浅拷贝 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Refe ...
- Python中的赋值(复制)、浅拷贝、深拷贝之间的区别
1.赋值: 只是复制了新对象的引用,不会开辟新的内存空间. 2.浅拷贝: 创建新对象,其内容是原对象的引用. 浅拷贝有三种形式:切片操作,工厂函数,copy模块中的copy函数. 如: ...
- JS对象复制(深拷贝、浅拷贝)
如何在 JS 中复制对象 在本文中,我们将从浅拷贝(shallow copy)和深拷贝(deep copy)两个方面,介绍多种 JS 中复制对象的方法. 在开始之前,有一些基础知识值得一提:Javas ...
随机推荐
- owin要跑起来
必须安装 Microsoft.Owin.Host.SystemWeb
- WindowsService 创建.安装.部署
windows服务的用法很适合用于一些长期跑的项目..不需要人工操作..不需要服务器一直登陆..很方便.. 不说废话..直接开整.. 启动VS2012..创建Windows服务项目.. 确定..创建成 ...
- Orchard源码分析(7.2):Controller相关
概述 默认情况下,ASP.NET MVC内置的DefaultControllerFactory负责Controller实例的创建.Orchard定义了一个继承自DefaultControllerFac ...
- 【转】nanosleep的精度与调度算法的关系 来自:bean.blog.chinaunix.net
nanosleep的精度与调度算法的关系 2011-12-03 13:05:17 分类: LINUX Heartwork前辈在我前一篇博文多线程条件下的计数器(2)中的回复中提到, na ...
- js中的全局变量和静态变量的使用, js 的调试?- 如果js出错, js引擎 就会停止, 这会 导致 后面的 html中 refer 该函数时, 会报错 函数为定义!!
效果里面的函数, 如show, hide,slideDown等, 这些都叫 "效果"函数, 但是里面可以包含动画, 也可以 不包含动画. 动画,是指 元素 的内容 是 逐渐 显示/ ...
- 在linux下运行apt-get update 时,报错/var/lib/apt/lists/lock
在运行apt-get update 时,报下面的错误: E: 无法获得锁 /var/lib/apt/lists/lock - open (11: Resource temporarily unavai ...
- php简单实用的操作文件工具类(创建、移动、复制、删除)
php简单实用好用的文件及文件夹复制函数和工具类(创建.移动.复制.删除) function recurse_copy($src,$dst) { // 原目录,复制到的目录 $dir = opend ...
- css定位之z-index问题分析
新手先去看看 CSS z-index 属性 CSS z-index 属性的使用方法和层级树的概念 ---------------------------------------------- ...
- CSS hack 汇总
1, IE条件注释法,微软官方推荐的hack方式. <!]> IE6以及IE6以上版本可识别 <![endif]--> <!]> 仅IE7可识别 <![end ...
- 再谈 X-UA-Compatible 兼容模式
如何理解 IE 的文档兼容模式(X-UA-Compatible)? IE 浏览器支持多种文档兼容模式,得以因此改变页面的渲染效果. IE9 模式支持全范围的既定行业标准,包括 HTML5(草案), W ...