C#深浅拷贝的深入解析

C#深浅拷贝的深入解析

拷贝是编程中的常见操作,其中深浅拷贝是我们需要重点关注的。本文将介绍深浅拷贝的概念和实现方法,让初学者掌握如何正确实现深浅拷贝。

概念

深浅拷贝是针对引用类型而言的。

  • 浅拷贝:将引用类型的变量复制一份,但是仍然是复制的引用,即两个引用变量还是指向同一个对象。
  • 深拷贝:将引用类型的变量复制一份,并且将其中的引用类型也复制一份,即两个引用变量指向的是两个不同的对象。

浅拷贝的实现

浅拷贝可以通过 C# 中的 MemberwiseClone() 方法来实现。

public class Student : ICloneable
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Teacher Teacher { get; set; }

    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

public class Teacher
{
    public int Id { get; set; }
    public string Name { get; set; }
}

如上代码示例中,Student 类包含了一个 Teacher 类型的引用变量。如果我们现在需要复制一个 Student 对象,只需要使用 MemberwiseClone() 方法即可。

Student student1 = new Student { Id = 1, Name = "小明", Teacher = new Teacher { Id = 1, Name = "张老师" }};
Student student2 = (Student)student1.Clone();

student2.Id = 2;
student2.Teacher.Name = "王老师";

Console.WriteLine($"student1.Name = {student1.Name}"); // 小明 
Console.WriteLine($"student2.Name = {student2.Name}"); // 小明
Console.WriteLine($"student1.Teacher.Name = {student1.Teacher.Name}"); // 王老师
Console.WriteLine($"student2.Teacher.Name = {student2.Teacher.Name}"); // 王老师

上述示例代码中,我们使用了 MemberwiseClone() 方法来浅拷贝 Student 对象,并修改了 student2 的属性值和 Teacher 对象的属性值。从输出结果可以看出,student2 和 student1 的 Name 属性相同,这是因为 Name 是一个值类型,而 Teacher 的 Name 属性值不同,这是因为 Teacher 本身是一个引用类型,此时修改了其值,student1 和 student2 指向的是同一个 Teacher 对象,因此输出结果都为 "王老师"。

深拷贝的实现

深拷贝需要遍历所有的引用类型,并将其也进行拷贝。一般采用序列化与反序列化,或者对每个引用类型的类手动实现 Clone() 方法。

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public class Student : ICloneable
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Teacher Teacher { get; set; }

    public object Clone()
    {
        var student = (Student)this.MemberwiseClone();
        student.Teacher = (Teacher)this.Teacher.Clone();
        return student;
    }
}

public class Teacher : ICloneable
{
    public int Id { get; set; }
    public string Name { get; set; }

    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

如上代码示例中,我们在 Student 类中的 Clone() 方法中对 Teacher 引用类型进行了拷贝,并且手动实现了 Teacher 类的 Clone() 方法来完成深拷贝。

还可以使用序列化实现深拷贝,示例代码如下:

public static T DeepCopy<T>(T obj)
{
    using (var ms = new MemoryStream())
    {
        var formatter = new BinaryFormatter();
        formatter.Serialize(ms, obj);
        ms.Position = 0;

        return (T)formatter.Deserialize(ms);
    }
}

示例说明:

Student student1 = new Student { Id = 1, Name = "小明", Teacher = new Teacher { Id = 1, Name = "张老师" }};
Student student3 = DeepCopy<Student>(student1);

student3.Id = 3;
student3.Teacher.Name = "王老师";

Console.WriteLine($"student1.Id = {student1.Id}"); // 1
Console.WriteLine($"student3.Id = {student3.Id}"); // 3
Console.WriteLine($"student1.Teacher.Name = {student1.Teacher.Name}"); // 张老师
Console.WriteLine($"student3.Teacher.Name = {student3.Teacher.Name}"); // 王老师

上述示例代码中,在 DeepCopy() 方法中使用了 BinaryFormatter 序列化和反序列化实现了深拷贝。输出结果与前一个示例相同,代码的实现更加简洁。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#深浅拷贝的深入解析 - Python技术站

(0)
上一篇 2023年5月31日
下一篇 2023年5月31日

相关文章

  • C# 模式匹配完全指南

    C# 模式匹配完全指南 本文旨在为C#开发者提供完整的模式匹配指南,包括使用 switch 语句,使用 is 表达式和模式表达式。了解模式匹配可以让你的代码更加简洁、易读和可维护。 使用 switch 语句进行模式匹配 switch 语句可以完成基本的模式匹配,通过模式匹配,可以避免大量的if语句,极大的增强代码的简洁性和可读性。 下面是一个用于判断对象类型…

    C# 2023年6月6日
    00
  • C#实现XML文件与DataTable、Dataset互转

    下面我为您详细讲解C#实现XML文件与DataTable、Dataset互转的完整攻略。 转换DataTable为XML文件 在C#中将DataTable转换为XML文件非常简单,我们可以通过DataTable的WriteXml方法来实现转换。该方法用于把DataTable中的数据写入到XML文件中,并可在需要时指定XML文件的路径及名称。具体的示例代码如下…

    C# 2023年5月31日
    00
  • C#实现简单的JSON序列化功能代码实例

    下面给出C#实现简单的JSON序列化功能的完整攻略,包含以下几个步骤: 1. 创建C#类以及对象 首先需要创建一个C#类,该类的属性用于存储需要序列化成JSON格式的数据。以下是一个示例类: public class Person { public string Name { get; set; } public int Age { get; set; } …

    C# 2023年5月31日
    00
  • WinForm相对路径的陷阱

    WinForm相对路径的陷阱是指在Windows窗体应用程序中使用相对路径时可能会遇到的问题。在WinForm应用程序中,使用相对路径可以方便地引用外部文件,例如资源文件、配置文件、图片等,但是如果不注意一些细节,就会出现问题。下面是WinForm相对路径的完整攻略。 1. 了解相对路径和绝对路径 在开始之前,我们需要了解相对路径和绝对路径的概念。相对路径是…

    C# 2023年6月1日
    00
  • 关于ObservableCollection的更新与不更新分析

    因为最近在WPF项目中,遇到ObservableCollection这个属性的频繁使用,一个一个坑跳过来,今天看到这个贴子 玩转INotifyPropertyChanged和ObservableCollection – 包建强 – 博客园 (cnblogs.com) 其中分析很透彻了,但是留了一点遗憾,而且在其中引起了一个想法,做一个项目来测试一下。 我们知…

    C# 2023年5月11日
    00
  • C# BinaryReader.ReadBytes – 读取字节数组

    BinaryReader.ReadBytes 方法是 .NET Framework 内置的一个方法,可以用来从流中读取指定长度的字节,并将其存储在字节数组中。该方法返回一个字节数组,表示从流中读取的数据。 使用该方法需要先创建一个 BinaryReader 实例,该实例包含了一个可以读取的流。然后可以调用 ReadBytes 方法来读取指定长度的字节。该方法…

    C# 2023年4月19日
    00
  • 如何搭建新的WPF项目框架

    如何搭建新的WPF项目框架 搭建新的WPF项目框架可以帮助我们更好地组织和管理WPF应用程序的代码。本文将提供详细的“如何搭建新的WPF项目框架”的完整攻略,包括如何创建项目结构、如何添加基础类以及两个示例。 创建项目结构 要创建新的WPF项目框架,我们需要执行以下步骤: 创建一个新的WPF应用程序项目。 在项目中创建一个名为“Infrastructure”…

    C# 2023年5月15日
    00
  • C#.NET字符串比较中忽略符号的方法

    C#.NET字符串比较时,如果需要忽略掉部分或全部符号,我们可以使用以下两种方法: 1. 使用System.Text.RegularExpressions.Regex类 使用System.Text.RegularExpressions.Regex类可以方便地实现忽略符号的字符串比较。代码示例如下: // 声明两个字符串 string str1 = &quot…

    C# 2023年6月1日
    00
合作推广
合作推广
分享本页
返回顶部