C#中深拷贝和浅拷贝
一:概念
内存:用来存储程序信息的介质。
指针:指向一块内存区域,通过它可以访问该内存区域中储存的程序信息。(C#也是有指针的)
值类型:struct(整形、浮点型、decimal的内部实现都是struct)、enum、可空类型
引用类型:class、interface、delegate、数组、object、string。
二:深拷贝和浅拷贝的认识:
举个例子:
Myclass a=new Myclass();
Myclass b=a;
首先,深、浅拷贝与上面的语句并没有任何关系,要区分深、浅拷贝,关键要看“=”是如何重载的。
深拷贝:不管是值类型还是引用类型,都在内存中新建一块储存块,该储存块的内容(由b指向)与被拷贝的储存块(由a指向)的内容相同,并新建一个指针(b)指向该新建的储存块。所以对b的操作是不会影响a。
浅拷贝:对于值类型,拷贝一份值的副本;对于引用类型,拷贝一份指针的副本(该副本仍然指向原指针指向的内存块,即a、b指向同一块内存)。对b的值类型进行操作,不会影响a;对b的引用类型进行操作,会影响a。
对于浅拷贝,有一种奇怪的现象,即:若a中包含一个string类型的字段,对a进行浅拷贝,赋值给b,在b中改变这个string类型的字段,a中string类型字段不受影响。string类型明明是引用类型,按照上面的理解,修改b中的string字段,a中的string字段也该作出相应的改变,这是为什么呢?
我们不妨看看string的定义,会发现string被readonly关键字修饰了,即改变string的值时,就会重新分配内存空间。有兴趣的话可以了解一下“C#字符串不可变性”。
三:string
String是引用类型。究其原因,是因为string对象是不可变的,包括长度和其中任何字符都是不可以改变的。
关于不可变数据类型,请参考:https://www.cnblogs.com/mushroom/p/4373951.html
string 对象称为不可变的(只读),因为一旦创建了该对象,就不能修改该对象的值。有的时候看来似乎修改了,实际是string经过了特殊处理,每次改变值时都会建立一个新的string对象,变量会指向这个新的对象,而原来的还是指向原来的对象,所以不会改变。这也是string效率低下的原因。如果经常改变string的值则应该使用StringBuilder而不使用string。
在例子中str1=”ab”,这时在内存中就将“ab”存下来,如果再创建字符串对象,其值也等于“ab”,str2=”ab”,则并非再重新分配内存空间,而是将之前保存的“ab”的地址赋给str2的引用,这就能印证例子2中的结果。而当str1=”abc”其值发生改变时,这时检查内存,发现不存在此字符串,则重新分配内存空间,存储“abc”,并将其地址赋给str1,而str2依然指向“ab”的地址。可以印证例子中的结果。
String是引用类型,只是编译器对其做了特殊处理。
四:实例(原型模式)
1)浅拷贝:
声明一个将要被克隆的类 clsShallow 和它将要包含的引用类型成员clsRefSalary类,clsShallow包含 CompanyName(静态字符串)、Age(值类型)、EmployeeName(字符串)、EmpSalary(引用类型)四个成员。

public class clsShallow
{
public static string CompanyName = "My Company";
public int Age;
public string EmployeeName;
public clsRefSalary EmpSalary; public clsShallow CreateShallowCopy(clsShallow inputcls)
{
return (clsShallow)inputcls.MemberwiseClone();
}
}
public class clsRefSalary
{
public clsRefSalary(int _salary)
{
Salary = _salary;
}
public int Salary;
}

再看如何调用:

static void Main()
{
// Creates an instance of clsShallow and assign values to its fields.
clsShallow objshallow = new clsShallow();
objshallow.Age = 25;
objshallow.EmployeeName = "Ahmed Eid";
// add the ref value to the objshallow
clsRefSalary clsref = new clsRefSalary(1000);
objshallow.EmpSalary = clsref; // Performs a shallow copy of m1 and assign it to m2.
clsShallow m2 = objshallow.CreateShallowCopy(objshallow);
m2.Age = 20;
m2.EmployeeName = "jay"; // then modify the clsref salary value to be 2000
clsref.Salary = 2000;
// so the m1 object salary value become 2000 Console.WriteLine(m2 == objshallow);
Console.WriteLine(objshallow.EmpSalary.Salary);
Console.WriteLine(m2.EmpSalary.Salary);
Console.WriteLine(objshallow.Age);
Console.WriteLine(m2.Age);
Console.WriteLine(objshallow.EmployeeName);
Console.WriteLine(m2.EmployeeName);
}

最后看运行结果:

根据结果我们进行分析:
浅拷贝:
1、浅拷贝创建了类的一个新实例。(由对象的同一性得知:如果两个引用如m2 、 objshallow指向同一个对象的实例,则(m2 == objshallow)为true,而结果显示为 false,所以m2 和objshallow分别指向不同的实例,而objshallow引用所指向的实例是新创建的。
2、对于对象(clsShallow)中的引用类型成员(clsRefSalary),引用被复制,但引用的实例没有被复制,即新创建实例中的引用成员(m2.EmpSalary)等于原实例的引用成员(objshallow.EmpSalary)。 因为改变 clsref.Salary 等于2000后,objshallow.EmpSalary 和m2.EmpSalary的Salary都改变了。其实可通过Console.WriteLine(objshallow.EmpSalary == m2.EmpSalary) 输出为true来解释。
3、值类型字段逐位复制到新实例。即改变m2.Age不影响objshallow.Age值。有人要问,string 为引用类型,为什么改变m2.EmployeeName = "jay"而objshallow.EmployeeName = "Ahmed Eid"没变呢?这是因为:字符串具有恒等性,一个字符串一旦被创建,我们就不能再将其变长、变短、或者改变其中的任何字符。
2) 深拷贝:
修改代码如下:

static void Main()
{
clsDeep objdeep = new clsDeep();
objdeep.Age = 25;
objdeep.EmployeeName = "Ahmed Eid"; // add the ref value
clsRefSalary clsref = new clsRefSalary(1000);
objdeep.EmpSalary = clsref; // Performs a shallow copy of m1 and assign it to m2.
clsDeep m2 = objdeep.CreateDeepCopy(objdeep); // then modify the clsref salary value to be 2000
clsref.Salary = 2000; // so the m1 object salary value become 2000
int EmpSalary = objdeep.EmpSalary.Salary;
m2.Age = 20;
m2.EmployeeName = "jay"; // then modify the clsref salary value to be 2000
clsref.Salary = 2000;
// so the m1 object salary value become 2000
Console.WriteLine(m2 == objdeep);
Console.WriteLine(objdeep.EmpSalary.Salary);
Console.WriteLine(m2.EmpSalary.Salary);
Console.WriteLine(objdeep.EmpSalary == m2.EmpSalary);
Console.WriteLine(objdeep.Age);
Console.WriteLine(m2.Age);
Console.WriteLine(objdeep.EmployeeName);
Console.WriteLine(m2.EmployeeName);
} [Serializable]
// serialize the classes in case of deep copy
public class clsDeep
{
public static string CompanyName = "My Company";
public int Age;
public string EmployeeName;
public clsRefSalary EmpSalary;
public clsDeep CreateDeepCopy(clsDeep inputcls)
{
MemoryStream m = new MemoryStream();
BinaryFormatter b = new BinaryFormatter();
b.Serialize(m, inputcls);
m.Position = 0;
return (clsDeep)b.Deserialize(m);
}
} [Serializable]
public class clsRefSalary
{
public clsRefSalary(int _salary)
{
Salary = _salary;
}
public int Salary;
}

记得加命名空间
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
查看结果:

深拷贝:
1、深拷贝创建了类的一个新实例
2、对于实例中的引用类型成员,创建引用类型成员对象的新副本。 ( objshallow.EmpSalary != m2.EmpSalary)
3、值类型字段逐位复制到新实例。
其实,浅拷贝和深拷贝的本质区别是实例中的引用类型成员如何拷贝, 浅拷贝复制引用,深拷贝创建新实例。
注:无论浅、深拷贝,静态成员都不会复制,因为静态成员属于类成员。
3)深复制方法

/// <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>(this 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);
}
}

C#中深拷贝和浅拷贝的更多相关文章
- python 中 深拷贝和浅拷贝的理解
在总结 python 对象和引用的时候,想到其实 对于python的深拷贝和浅拷贝也可以很好对其的进行理解. 在python中,对象的赋值的其实就是对象的引用.也就是说,当创建一个对象,然后赋给另外一 ...
- Python中深拷贝与浅拷贝的区别
转自:http://blog.csdn.net/u014745194/article/details/70271868 定义: 在Python中对象的赋值其实就是对象的引用.当创建一个对象,把它赋值给 ...
- C++中深拷贝与浅拷贝
浅拷贝和深拷贝 在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B.这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指 ...
- python中深拷贝与浅拷贝
# 1.浅拷贝(复制东西)a = [11,22,33] # 实际上是浅拷贝# 没有把这个变量的值赋进去,而是把另一个变量的地址拿过去了,就叫浅拷贝.b = a # print(id(a))# prin ...
- python中深拷贝和浅拷贝
python中所谓浅拷贝就是对引用的拷贝,所谓深拷贝就是对对象的资源的拷贝. 首先,对赋值操作我们要有以下认识: 赋值是将一个对象的地址赋值给一个变量,让变量指向该地址( 旧瓶装旧酒 ). 修改不可变 ...
- 关于Python中深拷贝与浅拷贝的理解(一)---概念
import copy a = [1, 2, 3, 4, ['a', 'b']] #原始对象 b = a #赋值,传对象的引用 c = copy.copy(a) #对象拷贝,浅拷贝 d = copy. ...
- iOS中深拷贝、浅拷贝和retain的区别
浅拷贝:浅拷贝是对object对象的指针拷贝,让指针指向同一块内存地址,“对象永远只有一个",浅拷贝使对象的引用计数器+1.代码如下: 可以看出不可变字符串的指针指向了同一地址,并没有重新开 ...
- Python中深拷贝与浅拷贝区别
浅拷贝, list值是可变的,str值不可变,只能重新赋值 a=b=c='wjx'print(a,b,c)c= 'jmy'#重新赋值了,所以内存分配了新的地址print(a,b,c)print(id( ...
- python 中深拷贝和浅拷贝的区别
通俗的理解,浅就是外面,深就是里面.浅拷贝的意思就是只拷贝外面的一层,深拷贝就是拷贝的里面的所有. 看两段代码: 元组: #!/usr/bin/env/python # -*-coding:utf-8 ...
随机推荐
- Python: pyinstaller打包exe(含file version信息)
最近项目上一直都是用Spyder直接运行.py文件的方式来执行每日的自动化程序,每天都要手动去点击Run来执行一次,所以考虑把.py文件直接打包成exe,然后用windows的task schedul ...
- 毕业回馈-89C51之数码管的使用
7段码的数码管由7个LED等共同组成,根据公共端的不同有共阴和共阳之分.现在很多数码管在7段码的基础上加了一个.即dp,其内部结构如下图所示: 公共端为LED灯的阴极,所以为共阴极接法: 公共端为阳极 ...
- mvc 读写txt文档
-----------------写入内容---------------- string userfile = "UserData.txt"; StreamWriter sw = ...
- 程序媛计划——python数据库
#实例:用数据库存储日记,实现日记本功能 #流程 #创建数据库 #coding:utf-8 import sqlite3 connect=sqlite3.connect('test.db') conn ...
- 欢迎使用CSDN-markdown编辑器a
这里写自定义目录标题 欢迎使用Markdown编辑器 新的改变 功能快捷键 合理的创建标题,有助于目录的生成 如何改变文本的样式 插入链接与图片 如何插入一段漂亮的代码片 生成一个适合你的列表 创建一 ...
- 用0x077CB531计算末尾0的个数
http://www.matrix67.com/blog/archives/3985 unsigned int v; // find the number of trailing zeros in ...
- iOS-电池图标【结合贝塞尔曲线控制电量显示】
基于UIView类:WKJBatteryView WKJBatteryView.h #import <UIKit/UIKit.h> @interface WKJBatteryView : ...
- crop和resize操作区别
crop:对图像进行剪切 resize:对图像进行伸缩 实践代码 import cv2 bb2d = [30, 30, 72 ,42] image = cv2.imread('car.png') pt ...
- WebDriverAPI(6)
在指定元素上方进行鼠标悬浮 测试网址 http://www.baidu.com Java语言版本实例 @Test public void roverOnElement() { driver.manag ...
- JS优先队列排序。出队时,先找出优先级最高的元素,再按照先进先出出队。
JS优先队列排序.出队时,先找出优先级最高的元素,再按照先进先出出队. /* * 优先队列 * 出队时,先找出优先级最高的元素,再按照先进先出出队. * */ function Queue(){ th ...