搜索
首页后端开发C#.Net教程C#浅拷贝和深拷贝实例解析

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

一、浅拷贝

1.什么是"浅拷贝":

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

2.有一个对象,包含引用类型的类成员和值类型的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(); //对引用类型实施浅复制
  }
}

3.测试拷贝后的效果

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

static void Main(string[] args)
{
  Room room1 = new Room(60);
  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 = 80;
 
  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;//复制当前引用类型成员的值到新对象
  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 = 0;
  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 = 0;
    return (bf.Deserialize(ms));
  }
}

   

5.测试拷贝后的效果

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

static void Main(string[] args)
   {
     Room room1 = new Room(60);
     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 = 80;
 
     Console.WriteLine("修改之后,结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema1._film._name, cinema1._room._maxSeat);
     Console.WriteLine("修改之后,新的结构成员的字段值为{0},引用类型成员的字段值为{1}", cinema2._film._name, cinema2._room._maxSeat);
 
     Console.ReadKey();
   }

   

结果:

C#浅拷贝和深拷贝实例解析

分析:

深拷贝后,两个对象的引用成员已经分离,改变原先对象引用类型成员的值并不会对复制对象的引用类型成员值造成影响。

更多C#浅拷贝和深拷贝实例解析相关文章请关注PHP中文网!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
char数组在C语言中如何使用char数组在C语言中如何使用Apr 03, 2025 pm 03:24 PM

char 数组在 C 语言中存储字符序列,声明为 char array_name[size]。访问元素通过下标运算符,元素以空终止符 '\0' 结尾,用于表示字符串终点。C 语言提供多种字符串操作函数,如 strlen()、strcpy()、strcat() 和 strcmp()。

C语言各种符号的使用方法C语言各种符号的使用方法Apr 03, 2025 pm 04:48 PM

C 语言中符号的使用方法涵盖算术、赋值、条件、逻辑、位运算符等。算术运算符用于基本数学运算,赋值运算符用于赋值和加减乘除赋值,条件运算符用于根据条件执行不同操作,逻辑运算符用于逻辑操作,位运算符用于位级操作,特殊常量用于表示空指针、文件结束标记和非数字值。

char在C语言字符串中的作用是什么char在C语言字符串中的作用是什么Apr 03, 2025 pm 03:15 PM

在 C 语言中,char 类型在字符串中用于:1. 存储单个字符;2. 使用数组表示字符串并以 null 终止符结束;3. 通过字符串操作函数进行操作;4. 从键盘读取或输出字符串。

char在C语言中如何处理特殊字符char在C语言中如何处理特殊字符Apr 03, 2025 pm 03:18 PM

C语言中通过转义序列处理特殊字符,如:\n表示换行符。\t表示制表符。使用转义序列或字符常量表示特殊字符,如char c = '\n'。注意,反斜杠需要转义两次。不同平台和编译器可能有不同的转义序列,请查阅文档。

c#多线程和异步的区别c#多线程和异步的区别Apr 03, 2025 pm 02:57 PM

多线程和异步的区别在于,多线程同时执行多个线程,而异步在不阻塞当前线程的情况下执行操作。多线程用于计算密集型任务,而异步用于用户交互操作。多线程的优势是提高计算性能,异步的优势是不阻塞 UI 线程。选择多线程还是异步取决于任务性质:计算密集型任务使用多线程,与外部资源交互且需要保持 UI 响应的任务使用异步。

char在C语言中如何进行类型转换char在C语言中如何进行类型转换Apr 03, 2025 pm 03:21 PM

在 C 语言中,char 类型转换可以通过:强制类型转换:使用强制类型转换符将一种类型的数据直接转换为另一种类型。自动类型转换:当一种类型的数据可以容纳另一种类型的值时,编译器自动进行转换。

C语言 sum 的作用是什么?C语言 sum 的作用是什么?Apr 03, 2025 pm 02:21 PM

C语言中没有内置求和函数,需自行编写。可通过遍历数组并累加元素实现求和:循环版本:使用for循环和数组长度计算求和。指针版本:使用指针指向数组元素,通过自增指针遍历高效求和。动态分配数组版本:动态分配数组并自行管理内存,确保释放已分配内存以防止内存泄漏。

char与wchar_t在C语言中的区别char与wchar_t在C语言中的区别Apr 03, 2025 pm 03:09 PM

在 C 语言中,char 和 wchar_t 的主要区别在于字符编码:char 使用 ASCII 或扩展 ASCII,wchar_t 使用 Unicode;char 占用 1-2 个字节,wchar_t 占用 2-4 个字节;char 适用于英语文本,wchar_t 适用于多语言文本;char 广泛支持,wchar_t 依赖于编译器和操作系统是否支持 Unicode;char 的字符范围受限,wchar_t 的字符范围更大,并使用专门的函数进行算术运算。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中