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

下面我将详细介绍一下 "C#浅拷贝和深拷贝实例解析" 的完整攻略。

一、浅拷贝和深拷贝的概念

在 C# 中,对象的拷贝方式有两种:浅拷贝和深拷贝。浅拷贝只是复制对象的引用,而不复制引用对象本身;深拷贝则是复制所有的引用对象。

二、浅拷贝和深拷贝的实现

1. 实现浅拷贝

在 C# 中,想要实现对象的浅拷贝,我们可以在该对象中添加一个 Clone() 方法。在 Clone() 方法中,我们只需要创建一个新的对象,并将原对象中所有的值类型成员复制给新对象,但对于引用类型的成员,我们只需要复制它们的引用即可。

接下来是一个浅拷贝示例:

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Address Address { get; set; }

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

class Address
{
    public string City { get; set; }
    public string Street { get; set; }
}

// 测试用例
Person person1 = new Person
{
    Name = "张三",
    Age = 18,
    Address = new Address { City = "北京", Street = "海淀区" }
};

Person person2 = person1.Clone();
person2.Address.City = "上海";

Console.WriteLine(person1.Address.City);  // 输出:上海

从上面的代码中可以看出,我们在 Person 类中添加了一个 Clone() 方法,而在这个方法中,我们调用了 Object 类的 MemberwiseClone() 方法,它能够创建一个当前对象的浅表副本。在该示例中,person1 和 person2 对象都拥有自己的地址引用,但这些引用指向的是同一个 Address 对象。所以当我们更新 person2.Address.City,实际上也会更新 person1.Address.City。

2. 实现深拷贝

那么如果我们想要实现深拷贝呢?在 C# 中,实现深拷贝的方式基本上有两种:手动拷贝和序列化。

手动实现深拷贝的方式是比较基础的。我们需要在创建新的对象时,对于引用类型的成员,我们需要递归每一个成员,依次创建新的对象并赋值。下面是一个手动实现深拷贝的示例:

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Address Address { get; set; }

    public Person Clone()
    {
        Address address = new Address { City = this.Address.City, Street = this.Address.Street };
        return new Person { Name = this.Name, Age = this.Age, Address = address };
    }
}

class Address
{
    public string City { get; set; }
    public string Street { get; set; }
}

// 测试用例
Person person1 = new Person
{
    Name = "张三",
    Age = 18,
    Address = new Address { City = "北京", Street = "海淀区" }
};

Person person2 = person1.Clone();
person2.Address.City = "上海";

Console.WriteLine(person1.Address.City);  // 输出:北京

从上面的代码中可以看出,我们在 Person 类中手动实现了 Clone() 方法。在这个方法中,我们递归的复制了每一个成员,生成了一个全新的对象。

当然,手动实现深拷贝是比较麻烦的,我们也可以使用 .NET 中的序列化和反序列化来实现深拷贝。我们只需要将携带了数据的对象序列化成二进制格式,再反序列化出新的对象即可实现深拷贝。下面是一个使用序列化实现深拷贝的示例:

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

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Address Address { get; set; }

    public Person Clone()
    {
        BinaryFormatter formatter = new BinaryFormatter();
        MemoryStream stream = new MemoryStream();
        formatter.Serialize(stream, this);
        stream.Position = 0;
        return (Person)formatter.Deserialize(stream);
    }
}

class Address
{
    public string City { get; set; }
    public string Street { get; set; }
}

// 测试用例
Person person1 = new Person
{
    Name = "张三",
    Age = 18,
    Address = new Address { City = "北京", Street = "海淀区" }
};

Person person2 = person1.Clone();
person2.Address.City = "上海";

Console.WriteLine(person1.Address.City);  // 输出:北京

从上面的代码中可以看出,我们在 Person 类中使用了 .NET 中的序列化和反序列化方法,先将 person1 对象序列化到一个内存流中,然后再从内存流中反序列化出 person2 对象。由于序列化和反序列化的过程都将创建新的对象,所以 person1 和 person2 对象拥有自己的地址引用,互不干扰。

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

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

相关文章

  • C#中Stopwatch的使用及说明

    C#中Stopwatch的使用及说明 什么是Stopwatch Stopwatch是C#中用来计算代码块执行时间的类。它通过记录时间戳(以当前系统时钟为基础),来计算代码块执行所需的时间。 导入Stopwatch命名空间 在使用Stopwatch类之前,需要导入System.Diagnostics命名空间,这可以通过在代码开头添加以下语句来实现: using…

    C# 2023年6月1日
    00
  • C#中结构体和字节数组转换实现

    C#中结构体和字节数组互相转换是常见的操作,结构体可以用来表示数据的存储,字节数组可以用来将数据在不同计算机或程序之间传输。以下是实现该操作的攻略。 1. 结构体与字节数组的转换 1.1 将结构体转换为字节数组 将结构体转换成字节数组需要用到C#中的Marshal类和SizeOf方法。SizeOf方法可以得到结构体的大小,Marshal类提供了各种Marsh…

    C# 2023年6月7日
    00
  • openfiledialog读取txt写入数据库示例

    下面是“openfiledialog读取txt写入数据库示例”的完整攻略。 1. 准备工作 在开始编写代码之前,我们需要做一些准备工作: 安装并配置好数据库软件(比如 MySQL 或 SQLite),并创建一个数据库和相关的表结构; 创建一个能够与数据库进行连接的程序,并引入第三方库(比如 pymysql)作为驱动; 准备一个包含数据的 txt 文本文件; …

    C# 2023年5月15日
    00
  • .NET垃圾回收器(GC)原理浅析

    . 标题 为了让读者更好地理解.NET垃圾回收器(GC)的原理,本文将从以下几个方面进行分析: 1. 垃圾回收的概念 首先,我们需要了解垃圾回收的概念。在.NET中,所有的对象都是分配在托管堆(Managed Heap)中的,而堆的管理和维护是由GC负责的。GC会定期检查堆中的对象,识别出哪些对象是不再被使用的,然后将其回收,释放所占用的空间。 2. 垃圾回…

    C# 2023年5月15日
    00
  • C#实现HTTP上传文件的方法

    C#实现HTTP上传文件的方法,一般采用POST方法,可以通过以下步骤实现: 构建HTTP请求参数:我们需要指定文件的路径、文件名称、文件类型以及服务器地址等等。 打开文件,并读取文件内容:需要使用File类或者FileStream类进行文件的读取。 将文件内容放入HTTP请求体中:使用Stream将文件内容放入HTTP请求体中。 发送HTTP请求:使用Ht…

    C# 2023年6月1日
    00
  • C#字符串的常用操作工具类代码分享

    我来详细讲解一下“C#字符串的常用操作工具类代码分享”的完整攻略。 一、介绍 随着C#语言的不断发展,对字符串的操作越发重要。本文主要介绍C#中字符串的常用操作工具类代码分享。 二、C#字符串操作示例 1. 字符串转换为大写 string str = "hello world"; string upperStr = str.ToUpper…

    C# 2023年5月31日
    00
  • ASP.NetCore使用Swagger实战

    Swagger是一种API文档生成工具,可以帮助我们快速生成API文档,并提供交互式API测试界面。在本文中,我们将详细讲解如何在ASP.NetCore项目中使用Swagger,包括环境搭建、代码实现、示例说明等。 环境搭建 在开始使用Swagger之前,我们需要先搭建好ASP.NetCore的开发环境。具体来说,我们需要安装以下软件: Visual Stu…

    C# 2023年5月16日
    00
  • Ajax实现评论中顶和踩功能的实例代码

    下面是Ajax实现评论中顶和踩功能的完整攻略。 1. 实现思路 实现评论中顶和踩功能,需要使用 Ajax 技术,通过向服务器端发送异步请求,实现对数据库中的数据进行增、删、改的操作。 一般而言,实现评论中顶和踩功能的流程如下: 点击“顶”或“踩”按钮; 发送 Ajax 请求到服务器端; 服务器端接收请求,根据请求的类型,在数据库中进行相应的操作; 服务器端将…

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