在有些时候,我们需要从数据库读取数据填充对象或从硬盘读取文件填充对象,但是这样做相对耗时。这时候我们就想到了对象的拷贝。本文即以实例形式解析了C#浅拷贝和深拷贝的用法。

C#中有两种类型变量,一种 是值类型变量,一种是引用类型变量。对于前者,copy是属于全盘复制;而对后者,一般的copy只是浅copy,相当于只传递一个引用指针一样。因此 对于后者进行真正copy的时候,也是最费事的,具体的说,必须为其实现ICloneable接口中提供的Clone方法。

一、浅拷贝

1.什么是"浅拷贝":

当针对一个对象浅拷贝的时候,对于对象的值类型成员,会复制其本身,对于对象的引用类型成员,仅仅复制对象引用,这个引用指向托管堆上的对象实例。

例如:有一个对象,包含引用类型的类成员和值类型的struct成员

即:Cinema包含 引用类型成员Room和值类型成员Film。

public class Room
{
public int _maxSeat; public Room(int maxSeat)
{
this._maxSeat = maxSeat;
}
} public struct Film
{
public string _name; public Film(string name)
{
this._name = name;
}
} public class Cinema
{
public Room _room;
public Film _film; public Cinema(Room room, Film film)
{
this._room = room;
this._film = film;
} public object Clone()
{
return MemberwiseClone(); //对引用类型实施浅复制
}
}

2.测试拷贝后的效果

①打印出原先对象  拷贝前值类型和引用类型成员的值 
②对原先对象拷贝,打印出复制对象值类型和引用类型成员的值 
③改变原先对象的值,再次打印原先对象的值类型和引用类型成员的值 
④再次打印复制对象值类型和引用类型成员的值

static void Main(string[] args)
{
Room room1 = new Room();
Film film1 = new Film("家园防线");
Cinema cinema1 = new Cinema(room1, film1);
Cinema cinema2 = (Cinema)cinema1.Clone();
Console.WriteLine("拷贝之前,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name,cinema1._room._maxSeat); Console.WriteLine("拷贝之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat); //修改拷贝之前引用类型的字段值
cinema1._film._name = "极品飞车";
cinema1._room._maxSeat = ; Console.WriteLine("修改之后,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name, cinema1._room._maxSeat);
Console.WriteLine("修改之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat); Console.ReadKey();
}

运行结果如下:

分析:

浅拷贝关键点是对引用类型拷贝的是对象引用,这个引用指向托管堆上的对象实例。改变原对应引用类型的值,会影响到复制对象。

二、深拷贝

1.什么是"深拷贝"

对引用成员指向的对象也进行复制,在托管堆上赋值原先对象实例所包含的数据,再在托管堆上创建新的对象实例。

2.通过对每个对象成员进行复制进行深拷贝

public object Clone()
{
Room room = new Room();
room._maxSeat = this._room._maxSeat;//复制当前引用类型成员的值到新对象 </span>
Film film = this._film; //值类型直接赋值
Cinema cinema = new Cinema(room, film);
return cinema;
}

3.也可以通过序列化和反序列化进行深拷贝

public object Clone1()
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, this); //复制到流中
ms.Position = ;
return (bf.Deserialize(ms));
}

4.采用序列化和反序列化深拷贝,但必须把所有的类打上[Serializable],测试代码如下:

[Serializable]
public class Room
{
public int _maxSeat; public Room()
{} public Room(int maxSeat)
{
this._maxSeat = maxSeat;
}
} [Serializable]
public struct Film
{
public string _name; public Film(string name)
{
this._name = name;
}
} [Serializable]
public class Cinema
{
public Room _room;
public Film _film; public Cinema(Room room, Film film)
{
this._room = room;
this._film = film;
} //浅拷贝
//public object Clone()
//{
// return MemberwiseClone(); //对引用类型实施浅复制
//} //深拷贝 对每个对象成员进行复制
public object Clone()
{
Room room = new Room();
room._maxSeat = this._room._maxSeat;//复制当前引用类型成员的值到新对象
Film film = this._film; //值类型直接赋值
Cinema cinema = new Cinema(room, film);
return cinema;
} //使用序列化和反序列化进行复制
public object Clone1()
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, this); //复制到流中
ms.Position = ;
return (bf.Deserialize(ms));
}
}
5.测试拷贝后的效果
static void Main(string[] args)
{
Room room1 = new Room();
Film film1 = new Film("家园防线");
Cinema cinema1 = new Cinema(room1, film1);
Cinema cinema2 = (Cinema)cinema1.Clone1();
Console.WriteLine("拷贝之前,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name,cinema1._room._maxSeat); Console.WriteLine("拷贝之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat); //修改拷贝之前引用类型的字段值
cinema1._film._name = "极品飞车";
cinema1._room._maxSeat = ; Console.WriteLine("修改之后,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name, cinema1._room._maxSeat);
Console.WriteLine("修改之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat); Console.ReadKey();
}
结果:
分析:
深拷贝后,两个对象的引用成员已经分离,改变原先对象引用类型成员的值
并不会对复制对象的引用类型成员值造成影响。

C# 浅拷贝与深拷贝(复制)的更多相关文章

  1. java List复制:浅拷贝与深拷贝

    Java的拷贝可以分为三种:浅拷贝(Shallow Copy).深拷贝(Deep Copy).延迟拷贝(Lazy Copy). 在java中除了基本数据类型之外(int,long,short等),还存 ...

  2. Javascript/js 的浅拷贝与深拷贝(复制)学习随笔

    js变量的数据类型值分基本类型值和引用类型值. 在ES6(ECMAScript6)以前,基本数据类型包括String.Number.Boolean.Undefined.Null. 基本类型值的复制(拷 ...

  3. 【转】Python中的赋值、浅拷贝、深拷贝介绍

    这篇文章主要介绍了Python中的赋值.浅拷贝.深拷贝介绍,Python中也分为简单赋值.浅拷贝.深拷贝这几种"拷贝"方式,需要的朋友可以参考下   和很多语言一样,Python中 ...

  4. 渐析java的浅拷贝和深拷贝

          首先来看看浅拷贝和深拷贝的定义:       浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值,这个方式被称为浅拷贝.       深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所 ...

  5. 关于JavaScript的浅拷贝和深拷贝

    在 JS 中有一些基本类型像是Number.String.Boolean,而对象就是像这样的东西{ name: 'Larry', skill: 'Node.js' },对象跟基本类型最大的不同就在于他 ...

  6. c#中浅拷贝和深拷贝的理解

    c#中拷贝有浅拷贝和深拷贝之分. 例如对象A,其中有值类型字段和引用类型字段: 1.浅拷贝: 对于值类型字段,直接逐位复制到新拷贝的副本对象中,修改副本的字段的值,不会影响源对象中字段的值: 对于引用 ...

  7. C#浅拷贝与深拷贝区别

    也许会有人这样解释C# 中浅拷贝与深拷贝区别: 浅拷贝是对引用类型拷贝地址,对值类型直接进行拷贝. 不能说它完全错误,但至少还不够严谨.比如:string 类型咋说? 其实,我们可以通过实践来寻找答案 ...

  8. IOS的浅拷贝和深拷贝

    什么是深拷贝和浅拷贝 浅拷贝:就是指针的复制,拷贝的指针跟原指针指向内存中的同一个位置的对象.至于对象的引用计数值是否+1,就是看拷贝的指针赋给给的变量是Strong类型的,还是week类型的. 如果 ...

  9. 关于python中赋值、浅拷贝、深拷贝之间区别的深入分析

    当重新学习了计算机基础课程<数据结构和算法分析>后再来看这篇自己以前写的博文,发现错误百出.python内置数据类型之所以会有这些特性,归根结底是它采用的是传递内存地址的方式,而不是传递真 ...

随机推荐

  1. c++的格式控制

    1: 每个iostream对象维持一个控制IO格式化细节的格式状态.标准库定义了一组操纵符来修改对象的格式状态.所谓操纵符是可用作输入或输出操作符的函数或对象.iostream和iomanip头文件中 ...

  2. orecle常用函数

    Oracle SQL 提供了用于执行特定操作的专用函数.这些函数大大增强了 SQL 语言的功能.函数可以接受零个或者多个输入参数,并返回一个输出结果. oracle 数据库中主要使用两种类型的函数 1 ...

  3. poj2349 Arctic Network - 最小生成树

    2017-08-04 16:19:13 writer:pprp 题意如下: Description The Department of National Defence (DND) wishes to ...

  4. forever让nodejs后台运行

    nodejs一般是当成一条用户命令执行的,当用户断开客户连接,运用也就停了,很烦人.如何让nodejs应用当成服务,在后台执行呢? 最简单的办法: $ nohup node app.js 但是,for ...

  5. ButterKnife使用详谈

    (1)ButterKnife是什么? 在开发过程中,我们总是会写大量的findViewById和点击事件,像初始view.设置view监听这样简单而重复的操作让人觉得特别麻烦,当然不会偷懒的程序员不是 ...

  6. spark UDAF

    感谢我的同事 李震给我讲解UDAF 网上找到的大部分都只有代码,但是缺少讲解,官网的的API有讲解,但是看不太明白.我还是自己记录一下吧,或许对其他人有帮助. 接下来以一个求几何平均数的例子来说明如何 ...

  7. C# 集合类 Array,Arraylist,List,Hashtable,Dictionary...

    我们用的比较多的非泛型集合类主要有 ArrayList类 和 HashTable类.我们经常用HashTable 来存储将要写入到数据库或者返回的信息,在这之间要不断的进行类型的转化,增加了系统装箱和 ...

  8. 牛客练习赛13D

    定义一个数字为幸运数字当且仅当它的所有数位都是4或者7.比如说,47.744.4都是幸运数字而5.17.467都不是.现在想知道在1...n的第k小的排列(permutation,https://en ...

  9. idea结合git使用三

    1.将本地代码提交到码云上面的步骤 2.先提交到本地Git的仓库,通过commit files 3.然后vcs----->git---->push,将本地仓库代码,推送到码云公司项目mas ...

  10. 监控和审计IBM InfoSphere BigInsights和Cloudera Hadoop的访问权限

    http://www.ithov.com/server/124456.shtml 您也将学习一个仅适用于 IBM InfoSphere BigInsights 的快速启动监控实现. 大数据骚动主要集中 ...