C#中浅拷贝与深拷贝(复制)

本文深入解析了C#中的深拷贝和浅拷贝概念,通过实例展示了如何实现对象的深拷贝和浅拷贝,以及它们在修改原始对象时对拷贝对象的影响。

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

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

 

一、浅拷贝

 

1.什么是"浅拷贝":

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

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

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

 

 
  1. public class Room

  2. {

  3. public int _maxSeat;

  4.  
  5. public Room(int maxSeat)

  6. {

  7. this._maxSeat = maxSeat;

  8. }

  9. }

  10.  
  11. public struct Film

  12. {

  13. public string _name;

  14.  
  15. public Film(string name)

  16. {

  17. this._name = name;

  18. }

  19. }

  20.  
  21. public class Cinema

  22. {

  23. public Room _room;

  24. public Film _film;

  25.  
  26. public Cinema(Room room, Film film)

  27. {

  28. this._room = room;

  29. this._film = film;

  30. }

  31.  
  32. public object Clone()

  33. {

  34. return MemberwiseClone(); //对引用类型实施浅复制

  35. }

  36. }

 

3.测试拷贝后的效果

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

 
  1. static void Main(string[] args)

  2. {

  3. Room room1 = new Room(60);

  4. Film film1 = new Film("家园防线");

  5. Cinema cinema1 = new Cinema(room1, film1);

  6. Cinema cinema2 = (Cinema)cinema1.Clone();

  7. Console.WriteLine("拷贝之前,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name,cinema1._room._maxSeat);

  8.  
  9. Console.WriteLine("拷贝之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);

  10.  
  11. //修改拷贝之前引用类型的字段值

  12. cinema1._film._name = "极品飞车";

  13. cinema1._room._maxSeat = 80;

  14.  
  15. Console.WriteLine("修改之后,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name, cinema1._room._maxSeat);

  16. Console.WriteLine("修改之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);

  17.  
  18. Console.ReadKey();

  19. }

运行结果如下:

 

分析:

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

 

二、深拷贝

 

1.什么是"深拷贝"

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

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

 
  1. public object Clone()

  2. {

  3. Room room = new Room();

  4. room._maxSeat = this._room._maxSeat;//复制当前引用类型成员的值到新对象 </span>

  5. Film film = this._film; //值类型直接赋值

  6. Cinema cinema = new Cinema(room, film);

  7. return cinema;

  8. }

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

 
  1. public object Clone1()

  2. {

  3. BinaryFormatter bf = new BinaryFormatter();

  4. MemoryStream ms = new MemoryStream();

  5. bf.Serialize(ms, this); //复制到流中

  6. ms.Position = 0;

  7. return (bf.Deserialize(ms));

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

 
  1. [Serializable]

  2. public class Room

  3. {

  4. public int _maxSeat;

  5.  
  6. public Room()

  7. {}

  8.  
  9. public Room(int maxSeat)

  10. {

  11. this._maxSeat = maxSeat;

  12. }

  13. }

  14.  
  15. [Serializable]

  16. public struct Film

  17. {

  18. public string _name;

  19.  
  20. public Film(string name)

  21. {

  22. this._name = name;

  23. }

  24. }

  25.  
  26. [Serializable]

  27. public class Cinema

  28. {

  29. public Room _room;

  30. public Film _film;

  31.  
  32. public Cinema(Room room, Film film)

  33. {

  34. this._room = room;

  35. this._film = film;

  36. }

  37.  
  38. //浅拷贝

  39. //public object Clone()

  40. //{

  41. // return MemberwiseClone(); //对引用类型实施浅复制

  42. //}

  43.  
  44. //深拷贝 对每个对象成员进行复制

  45. public object Clone()

  46. {

  47. Room room = new Room();

  48. room._maxSeat = this._room._maxSeat;//复制当前引用类型成员的值到新对象

  49. Film film = this._film; //值类型直接赋值

  50. Cinema cinema = new Cinema(room, film);

  51. return cinema;

  52. }

  53.  
  54. //使用序列化和反序列化进行复制

  55. public object Clone1()

  56. {

  57. BinaryFormatter bf = new BinaryFormatter();

  58. MemoryStream ms = new MemoryStream();

  59. bf.Serialize(ms, this); //复制到流中

  60. ms.Position = 0;

  61. return (bf.Deserialize(ms));

  62. }

  63. }

5.测试拷贝后的效果

 
  1. static void Main(string[] args)

  2. {

  3. Room room1 = new Room(60);

  4. Film film1 = new Film("家园防线");

  5. Cinema cinema1 = new Cinema(room1, film1);

  6. Cinema cinema2 = (Cinema)cinema1.Clone1();

  7. Console.WriteLine("拷贝之前,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name,cinema1._room._maxSeat);

  8.  
  9. Console.WriteLine("拷贝之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);

  10.  
  11. //修改拷贝之前引用类型的字段值

  12. cinema1._film._name = "极品飞车";

  13. cinema1._room._maxSeat = 80;

  14.  
  15. Console.WriteLine("修改之后,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name, cinema1._room._maxSeat);

  16. Console.WriteLine("修改之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);

  17.  
  18. Console.ReadKey();

  19. }

结果:

分析:

深拷贝后,两个对象的引用成员已经分离,改变原先对象引用类型成员的值

并不会对复制对象的引用类型成员值造成影响。

 

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.youkuaiyun.com/bigpudding24/article/details/48490145

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值