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日

相关文章

  • asp.net中使用log4net详解

    ASP.NET中使用log4net详解 什么是log4net log4net是Apache的一个开源项目,其目的是为.NET日志输出提供一个高效、灵活且可扩展的框架。log4net提供了丰富的日志记录机制,能够强化应用程序的可维护性和稳定性,将应用程序中各种事件输出到各种目标(文件、数据库、控制台等)。 如何使用log4net 步骤一:在项目中引用log4n…

    C# 2023年5月31日
    00
  • C#中的匿名函数、lambda表达式解读

    C#中的匿名函数、lambda表达式解读 在C#中,匿名函数和lambda表达式提供了更强大、更简洁的代码实现方式,这两个概念通常都是一起出现的。 匿名函数 匿名函数就是没有名字的函数,在C#中可以使用delegate来定义。匿名函数主要有以下两种形式: delegate (parameters) { statements } delegate { stat…

    C# 2023年6月1日
    00
  • C#条码生成及打印实例代码

    下面就为大家介绍一下“C#条码生成及打印实例代码”的完整攻略,包含以下几个步骤: 步骤1:了解条码生成原理 在了解具体的生成实现之前,我们需要先了解一下条码生成的基本原理和常用的编码方式。常用的编码方式包括Code39、Code128、EAN13等多种类型,每种类型的编码方式也不尽相同。 步骤2:引用条码生成库 在C#编程中,我们可以引用一些常用的条码生成库…

    C# 2023年5月31日
    00
  • C#使用private font改变PDF文件的字体详解

    下面是 “C#使用private font改变PDF文件的字体详解” 的完整攻略。 什么是Private Font Private Font是一种自定义字体,可以正常安装和使用,但在未安装该字体的计算机上会出现显示问题。因此我们需要在程序中安装该字体,在PDF文件中使用该字体。 安装Private Font 首先在项目目录下新建一个名为“Fonts”的文件夹…

    C# 2023年6月3日
    00
  • .Net Core简单使用Mvc内置的Ioc(续)

    .NET Core简单使用Mvc内置的Ioc(续) 在上一篇攻略中,我们介绍了如何在.NET Core应用程序中使用Mvc内置的Ioc容器。在本攻略中,我们将继续介绍如何使用Mvc内置的Ioc容器,并提供两个示例说明。 1. 注册服务 在.NET Core应用程序中,可以使用IServiceCollection接口的AddTransient、AddScope…

    C# 2023年5月16日
    00
  • C#实现类型的比较示例详解

    C#实现类型的比较示例详解 引言 C#是一门强类型的语言,在C#中,我们需要对不同的数据类型进行比较。因此,C#提供了多种方法来进行类型的比较。本文将介绍C#中实现类型比较的方法。 基本类型的比较 在C#中,基本类型的比较可以直接使用“==”和“!=”运算符。下面是一个示例: int a = 10; int b = 20; bool result = a =…

    C# 2023年5月14日
    00
  • 浅谈ASP.NET Core 中间件详解及项目实战

    ASP.NET Core 中间件是一种处理HTTP请求和响应的机制。中间件可以在请求到达控制器之前或响应返回给客户端之前执行一些操作。本文将详细讲解ASP.NET Core中间件的使用方法及项目实战。 什么是ASP.NET Core中间件? ASP.NET Core中间件是一种处理HTTP请求和响应的机制。中间件可以在请求到达控制器之前或响应返回给客户端之前…

    C# 2023年5月16日
    00
  • 在WinForm应用程序中快速实现多语言的处理的方法

    为WinForm应用程序添加多语言支持,可以让应用程序支持不同的语言,从而满足不同用户的需求。在以下攻略中,我们将介绍如何在WinForm应用程序中实现多语言的处理。 1. 收集字符串资源 在WinForm应用程序中,所有用到的字符串都应该作为字符串资源进行收集。在Visual Studio中,可以使用资源文件(.resx)来收集字符串资源。打开项目的属性窗…

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