当前位置:   article > 正文

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

c# byte[] =是深拷贝还是浅拷贝

 

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

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

 

一、浅拷贝

 

1.什么是"浅拷贝":

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

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

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

 

  1. public class Room
  2. {
  3. public int _maxSeat;
  4. public Room(int maxSeat)
  5. {
  6. this._maxSeat = maxSeat;
  7. }
  8. }
  9. public struct Film
  10. {
  11. public string _name;
  12. public Film(string name)
  13. {
  14. this._name = name;
  15. }
  16. }
  17. public class Cinema
  18. {
  19. public Room _room;
  20. public Film _film;
  21. public Cinema(Room room, Film film)
  22. {
  23. this._room = room;
  24. this._film = film;
  25. }
  26. public object Clone()
  27. {
  28. return MemberwiseClone(); //对引用类型实施浅复制
  29. }
  30. }

 

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. Console.WriteLine("拷贝之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);
  9. //修改拷贝之前引用类型的字段值
  10. cinema1._film._name = "极品飞车";
  11. cinema1._room._maxSeat = 80;
  12. Console.WriteLine("修改之后,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name, cinema1._room._maxSeat);
  13. Console.WriteLine("修改之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);
  14. Console.ReadKey();
  15. }

运行结果如下:

 

分析:

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

 

二、深拷贝

 

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. public Room()
  6. {}
  7. public Room(int maxSeat)
  8. {
  9. this._maxSeat = maxSeat;
  10. }
  11. }
  12. [Serializable]
  13. public struct Film
  14. {
  15. public string _name;
  16. public Film(string name)
  17. {
  18. this._name = name;
  19. }
  20. }
  21. [Serializable]
  22. public class Cinema
  23. {
  24. public Room _room;
  25. public Film _film;
  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. //深拷贝 对每个对象成员进行复制
  37. public object Clone()
  38. {
  39. Room room = new Room();
  40. room._maxSeat = this._room._maxSeat;//复制当前引用类型成员的值到新对象
  41. Film film = this._film; //值类型直接赋值
  42. Cinema cinema = new Cinema(room, film);
  43. return cinema;
  44. }
  45. //使用序列化和反序列化进行复制
  46. public object Clone1()
  47. {
  48. BinaryFormatter bf = new BinaryFormatter();
  49. MemoryStream ms = new MemoryStream();
  50. bf.Serialize(ms, this); //复制到流中
  51. ms.Position = 0;
  52. return (bf.Deserialize(ms));
  53. }
  54. }
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. Console.WriteLine("拷贝之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);
  9. //修改拷贝之前引用类型的字段值
  10. cinema1._film._name = "极品飞车";
  11. cinema1._room._maxSeat = 80;
  12. Console.WriteLine("修改之后,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name, cinema1._room._maxSeat);
  13. Console.WriteLine("修改之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);
  14. Console.ReadKey();
  15. }
结果:
分析:
深拷贝后,两个对象的引用成员已经分离,改变原先对象引用类型成员的值
并不会对复制对象的引用类型成员值造成影响。







转载于:https://www.cnblogs.com/peterYong/p/6556628.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/68356
推荐阅读
相关标签
  

闽ICP备14008679号