一:概念

内存:用来存储程序信息的介质。

指针:指向一块内存区域,通过它可以访问该内存区域中储存的程序信息。(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#中深拷贝和浅拷贝的更多相关文章

  1. python 中 深拷贝和浅拷贝的理解

    在总结 python 对象和引用的时候,想到其实 对于python的深拷贝和浅拷贝也可以很好对其的进行理解. 在python中,对象的赋值的其实就是对象的引用.也就是说,当创建一个对象,然后赋给另外一 ...

  2. Python中深拷贝与浅拷贝的区别

    转自:http://blog.csdn.net/u014745194/article/details/70271868 定义: 在Python中对象的赋值其实就是对象的引用.当创建一个对象,把它赋值给 ...

  3. C++中深拷贝与浅拷贝

    浅拷贝和深拷贝 在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B.这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指 ...

  4. python中深拷贝与浅拷贝

    # 1.浅拷贝(复制东西)a = [11,22,33] # 实际上是浅拷贝# 没有把这个变量的值赋进去,而是把另一个变量的地址拿过去了,就叫浅拷贝.b = a # print(id(a))# prin ...

  5. python中深拷贝和浅拷贝

    python中所谓浅拷贝就是对引用的拷贝,所谓深拷贝就是对对象的资源的拷贝. 首先,对赋值操作我们要有以下认识: 赋值是将一个对象的地址赋值给一个变量,让变量指向该地址( 旧瓶装旧酒 ). 修改不可变 ...

  6. 关于Python中深拷贝与浅拷贝的理解(一)---概念

    import copy a = [1, 2, 3, 4, ['a', 'b']] #原始对象 b = a #赋值,传对象的引用 c = copy.copy(a) #对象拷贝,浅拷贝 d = copy. ...

  7. iOS中深拷贝、浅拷贝和retain的区别

    浅拷贝:浅拷贝是对object对象的指针拷贝,让指针指向同一块内存地址,“对象永远只有一个",浅拷贝使对象的引用计数器+1.代码如下: 可以看出不可变字符串的指针指向了同一地址,并没有重新开 ...

  8. Python中深拷贝与浅拷贝区别

    浅拷贝, list值是可变的,str值不可变,只能重新赋值 a=b=c='wjx'print(a,b,c)c= 'jmy'#重新赋值了,所以内存分配了新的地址print(a,b,c)print(id( ...

  9. python 中深拷贝和浅拷贝的区别

    通俗的理解,浅就是外面,深就是里面.浅拷贝的意思就是只拷贝外面的一层,深拷贝就是拷贝的里面的所有. 看两段代码: 元组: #!/usr/bin/env/python # -*-coding:utf-8 ...

随机推荐

  1. [Xamarin]我的Xamarin填坑之旅(一)

    一想到明天是星期五,不对,是今天,心里就很激动,毕竟明天没课.激动之余,来写一篇博客,记录一下最近踏坑Xamarin开发校园助手APP的一些事儿.也许更像是一篇流水账. 在扯Xamarin之前,有必要 ...

  2. S11 day 97 -98天 Luffycity项目

    1. 建模 from django.db import models from django.contrib.contenttypes.fields import GenericForeignKey, ...

  3. Mysql 练习题一

    库操作: 1. 创建 数据库  create database db1; 2. 使用数据库 use db1 3. 查看表  show tables; 4. 删除  drop database db1  ...

  4. perl(ExtUtils::Embed)依赖包

       perl(ExtUtils::Embed) 被 ****需要    yum install perl-ExtUtils-Embed即可

  5. 1.在html中引入js文件和Jquery框架

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 四,php异常处理

    1,异常处理 异常处理用于在指定的异常或错误发生时,改变脚本的正常执行流程. <?php try{ //错误或异常 }catch (Exception $ex){ //处理异常 //抛出异常 } ...

  7. Python中线程与互斥锁

    了解之前我们先了解一下什么是多任务? 概念: 几个不同的事件在同时运行就是多任务, 这样的话, 我们有牵扯到了真的多任务, 假的多任务; 并行: 真的多任务, 通过电脑的核数来确定 并发: 假的多任务 ...

  8. 安装SQL Server 2016出错提示:需要安装oracle JRE7 更新 51(64位)或更高版本完美解决办法

    错误提示原因:安装时检测出电脑没有安装JDK,而且是版本7(其他版本不行) 解决方法:先进下面这个网站安装JDK,安装好后配置环境变量,然后重新安装SQL Server 2016即可 http://w ...

  9. Java Web入门学习(三)Maven的配置与使用国内仓库

    一.Maven下载与配置 下载好的压缩包,压缩到D盘,或者其他盘符. 新建系统环境变量 MAVEN_HOME  值是压缩好的Maven目录. 比如: D:\apache-maven- 在path环境变 ...

  10. (转) mysqldumpslow使用说明总结

    原文:http://blog.csdn.net/langkeziju/article/details/49301993 mysqldumpslow使用说明mysqldumpslow --helpUsa ...