当前位置: 首页 > news >正文

C# 深层副本与浅层副本 深拷贝与浅拷贝

C# 深层副本与浅层副本

数据复制是编程中的重要任务。 对象是 OOP 中的复合数据类型。 对象中的成员字段可以按值或按引用存储。 可以以两种方式执行复制。

浅表副本将所有值和引用复制到新实例中。 引用所指向的数据不会被复制; 仅指针被复制。 新的引用指向原始对象。 对引用成员的任何更改都会影响两个对象。

深层副本将所有值复制到新实例中。 如果成员存储为引用,则深层副本将对正在引用的数据执行深层副本。 创建一个引用对象的新副本。 并存储指向新创建对象的指针。 对这些引用对象的任何更改都不会影响该对象的其他副本。 深拷贝是完全复制的对象。

如果成员字段是值类型,则将对该字段进行逐位复制。 如果该字段是引用类型,则复制引用,但不是复制引用的对象。 因此,原始对象中的引用和克隆对象中的引用指向同一对象。 (来自 programmingcorner.blogspot.com 的明确解释)

C# 浅表复制

以下程序执行浅表复制。

Program.
using System;namespace ShallowCopy
{class Color{public int red;public int green;public int blue;public Color(int red, int green, int blue){this.red = red;this.green = green;this.blue = blue;}}class MyObject : ICloneable{public int id;public string size;public Color col;public MyObject(int id, string size, Color col){this.id = id;this.size = size;this.col = col;}public object Clone(){return new MyObject(this.id, this.size, this.col);}public override string ToString(){var s = String.Format("id: {0}, size: {1}, color:({2}, {3}, {4})",this.id, this.size, this.col.red, this.col.green, this.col.blue);return s;}}class Program{static void Main(string[] args){var col = new Color(23, 42, 223);var obj1 = new MyObject(23, "small", col);var obj2 = (MyObject) obj1.Clone();obj2.id += 1;obj2.size = "big";obj2.col.red = 255;Console.WriteLine(obj1);Console.WriteLine(obj2);}}
}

这是一个浅表副本的示例。 我们定义了两个自定义对象:MyObjectColor。 MyObject对象将引用 Color 对象。

class MyObject : ICloneable

我们应该为要克隆的对象实现ICloneable接口。

public object Clone()
{return new MyObject(this.id, this.size, this.col);
}

ICloneable接口迫使我们创建Clone()方法。 此方法返回具有复制值的新对象。

var col = new Color(23, 42, 223);  

我们创建 Color 对象的实例。

var obj1 = new MyObject(23, "small", col);

创建MyObject类的实例。 Color对象的实例传递给构造函数。

var obj2 = (MyObject) obj1.Clone();

我们创建 obj1 对象的浅表副本,并将其分配给 obj2 变量。 Clone()方法返回Object,我们期望MyObject。 这就是我们进行显式转换的原因。

obj2.id += 1;
obj2.size = "big";         
obj2.col.red = 255;

在这里,我们修改复制对象的成员字段。 我们增加 id,将大小更改为“大”,然后更改颜色对象的红色部分。

Console.WriteLine(obj1);
Console.WriteLine(obj2);

Console.WriteLine()方法调用obj2对象的ToString()方法,该方法返回对象的字符串表示形式。

$ dotnet run
id: 23, size: small, color:(255, 42, 223)
id: 24, size: big, color:(255, 42, 223)

我们可以看到 ID 是不同的(23 对 24)。 大小不同(“小”与“大”)。 但是,这两个实例的颜色对象的红色部分相同(255)。 更改克隆对象的成员值(id,大小)不会影响原始对象。 更改引用对象(col)的成员也影响了原始对象。 换句话说,两个对象都引用内存中的同一颜色对象。

C# 深层复制

要更改此行为,我们接下来将做一个深层复制。

Program.
using System;namespace DeepCopy
{class Color : ICloneable{public int red;public int green;public int blue;public Color(int red, int green, int blue){this.red = red;this.green = green;this.blue = blue;}public object Clone(){return new Color(this.red, this.green, this.blue);}}class MyObject : ICloneable{public int id;public string size;public Color col;public MyObject(int id, string size, Color col){this.id = id;this.size = size;this.col = col;}public object Clone(){return new MyObject(this.id, this.size,(Color)this.col.Clone());}public override string ToString(){var s = String.Format("id: {0}, size: {1}, color:({2}, {3}, {4})",this.id, this.size, this.col.red, this.col.green, this.col.blue);return s;}}class Program{static void Main(string[] args){var col = new Color(23, 42, 223);var obj1 = new MyObject(23, "small", col);var obj2 = (MyObject) obj1.Clone();obj2.id += 1;obj2.size = "big";obj2.col.red = 255;Console.WriteLine(obj1);Console.WriteLine(obj2);}}
}

在此程序中,我们对对象执行深层复制。

class Color : ICloneable

现在,Color 类实现了ICloneable接口。

public object Clone()
{return new Color(this.red, this.green, this.blue);
}

我们也为Color类提供了Clone()方法。 这有助于创建引用对象的副本。

public object Clone()
{return new MyObject(this.id, this.size, (Color) this.col.Clone());
}

当我们克隆MyObject时,我们根据 col 引用类型调用Clone()方法。 这样,我们也可以获得颜色值的副本。

$ dotnet run
id: 23, size: small, color:(23, 42, 223)
id: 24, size: big, color:(255, 42, 223)

现在,所引用的 Color 对象的红色部分不再相同。 原始对象保留了其先前的值(23)。

相关文章:

C# 深层副本与浅层副本 深拷贝与浅拷贝

C# 深层副本与浅层副本 数据复制是编程中的重要任务。 对象是 OOP 中的复合数据类型。 对象中的成员字段可以按值或按引用存储。 可以以两种方式执行复制。 浅表副本将所有值和引用复制到新实例中。 引用所指向的数据不会被复制; 仅指针被复制。 新的引用指向原始…...

CH06_Lambda表达式

第6章:Lambda表达式 本章目标 为什么要学习C#编程语言 了解C#相关常识 C#开发工具Visual Studio安装 掌握C#程序的开发步骤 掌握C#的注释 掌握C#的常用转义符 本章内容 lambda表达式演变史 C# 匿名函数的演变历史可以追溯到 C# 语言的不同版本,…...

大模型本地部署实践:Ollama+Open-WebUI(MacOS)

目录 什么是Ollama Ollama安装 对话界面可视化?Open-WebUI! 安装Open-WebUI 什么是Ollama Ollama是一个为简化大语言模型本地部署与交互的开源框架。它提供了用户友好的接口,帮助开发者和模型爱好者在没有依赖外部API的基础上高效地运行、…...

JavaScript——DOM编程、JS的对象和JSON

一、DOM编程 DOM(Document Object Model)编程:就是使用document对象的API,完成对网页HTML文档进行动态修改,以实现网页数据,和样式动态变化效果的编程。 (一)DOM获取元素的多种方法 1.查找元素的函数 getElementById("id值…...

SIMCom芯讯通A7680C在线升级:FTP升级成功;http升级腾讯云对象储存的文件失败;http升级私有服务器的文件成功

从事嵌入式单片机的工作算是符合我个人兴趣爱好的,当面对一个新的芯片我即想把芯片尽快搞懂完成项目赚钱,也想着能够把自己遇到的坑和注意事项记录下来,即方便自己后面查阅也可以分享给大家,这是一种冲动,但是这个或许并不是原厂希望的,尽管这样有可能会牺牲一些时间也有哪天原…...

OSRM docker环境启动

命令一把梭 wget https://download.geofabrik.de/asia/china-latest.osm.pbf docker pull osrm/osrm-backend docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-extract -p /opt/car.lua /data/china-latest.osm.pbf docker run -t -v "${PWD}:/data&q…...

Vue3 动态获取 assets 文件夹图片

我真服了Vue3 这个老六了,一个简单图片src 赋值搞得那么复杂. //item.type 是我遍历类型的类型参数 <img alt"吐槽大会" :src"getAssetUrl(item.type)" /> 基于 Vue2 的Webpack 处理,还不错,可以用/ 这种绝对路径,可以接受,虽然多了个require很不爽…...

<项目代码>YOLOv8 草莓成熟识别<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…...

代码随想录算法训练营第五十一天|Day51 图论

岛屿数量 深搜 https://www.programmercarl.com/kamacoder/0099.%E5%B2%9B%E5%B1%BF%E7%9A%84%E6%95%B0%E9%87%8F%E6%B7%B1%E6%90%9C.html 思路 #include <stdio.h> #define MAX_SIZE 50 int grid[MAX_SIZE][MAX_SIZE]; int visited[MAX_SIZE][MAX_SIZE]; int N, M; …...

uniapp 自定义加载组件,全屏加载,局部加载 (微信小程序)

效果图 全屏加载 页面加载使用 局部加载 列表加载里面使用 使用gif html <template><view><view class"" v-if"typeFullScreen"><view class"loading" v-if"show"><view class""><i…...

STM32完全学习——系统时钟设置

一、时钟框图的解读 首先我们知道STM32在上电初始化之后使用的是内部的HSI未经过分频直接通过SW供给给系统时钟&#xff0c;由于内部HSI存在较大的误差&#xff0c;因此我们在系统完成上电初始化&#xff0c;之后需要将STM32的时钟切换到外部HSE作为系统时钟&#xff0c;那么我…...

Github 2024-11-16Rust开源项目日报 Top10

根据Github Trendings的统计,今日(2024-11-16统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Go项目1Python项目1Lapce:用 Rust 编写的极快且强大的代码编辑器 创建周期:2181 天开发语言:Rust协议类型:Apache License 2.0St…...

CH03_反射

第3章&#xff1a;反射 本章目标 掌握反射的原理 熟悉反射的基本运用 本章内容 反射是什么 C# 编译运行过程 首先我们在VS点击编译的时候&#xff0c;就会将C#源代码编译成程序集 程序集以可执行文件 (.exe) 或动态链接库文件 (.dll) 的形式实现 程序集中包含有Microsoft …...

vue2侧边导航栏路由

<template><div><!-- :default-active"$route.path" 和index对应其路径 --><el-menu:default-active"active"class"el-menu-vertical-demo"background-color"#545c64"text-color"#fff"active-text-col…...

core 不可变类型 线程安全 record

当一个类型的对象在创建时被指定状态后&#xff0c;就不会再变化的对象&#xff0c;我们称之为不可变类型。这种类型是线程安全的&#xff0c;不需要进行线程同步&#xff0c;非常适合并行计算的数据共享。它减少了更新对象会引起各种bug的风险&#xff0c;更为安全。 System.D…...

linux之调度管理(8)-SMP cpu 的 psci启动

一、psci介绍 psci是arm提供的一套电源管理接口&#xff0c;当前一共包含0.1、0.2和1.0三个版本。它可被用于以下场景&#xff1a; &#xff08;1&#xff09;cpu的idle管理 &#xff08;2&#xff09;cpu hotplug以及secondary cpu启动 &#xff08;3&#xff09;系统shutdo…...

review-消息中间件MQ

RabbitMQ RabbitMQ&#xff0c;作为当今流行的开源消息代理软件&#xff0c;以其卓越的可靠性、灵活性和易用性在微服务架构和分布式系统中扮演着至关重要的角色。它不仅能够确保消息在不同系统组件间的高效传递&#xff0c;还能通过其高级消息队列协议&#xff08;AMQP&#x…...

leetcode400第N位数字

代码 class Solution {public int findNthDigit(int n) {int base 1;//位数int weight 9;//权重while(n>(long)base*weight){//300n-base*weight;base;weight*10;}//n111 base3 weight900;n--;int res (int)Math.pow(10,base-1)n/base;int index n%base;return String…...

前端网页开发学习(HTML+CSS+JS)有这一篇就够!

目录 HTML教程 ▐ 概述 ▐ 基础语法 ▐ 文本标签 ▐ 列表标签 ▐ 表格标签 ▐ 表单标签 CSS教程 ▐ 概述 ▐ 基础语法 ▐ 选择器 ▐ 修饰文本 ▐ 修饰背景 ▐ 透明度 ▐ 伪类 ▐ 盒子模型 ▐ 浮动 ▐ 定位 JavaScript教程 ▐ 概述 ▐ 基础语法 ▐ 函数 …...

CSS遮罩:mask

CSS属性 mask 允许使用者通过遮罩或者裁切特定区域的图片的方式来隐藏一个元素的部分或者全部可见区域。 // 一般用位图图片做遮罩 mask: url(~/assets/images/mask.png); mask-size: 100% 100%;// 使用 SVG 图形中的形状来做遮罩 mask: url(~/assets/images/mask.svg#star);…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)

目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 ​编辑​编辑 UDP的特征 socke函数 bind函数 recvfrom函数&#xff08;接收函数&#xff09; sendto函数&#xff08;发送函数&#xff09; 五、网络编程之 UDP 用…...

【1】跨越技术栈鸿沟:字节跳动开源TRAE AI编程IDE的实战体验

2024年初&#xff0c;人工智能编程工具领域发生了一次静默的变革。当字节跳动宣布退出其TRAE项目&#xff08;一款融合大型语言模型能力的云端AI编程IDE&#xff09;时&#xff0c;技术社区曾短暂叹息。然而这一退场并非终点——通过开源社区的接力&#xff0c;TRAE在WayToAGI等…...

【Java】Ajax 技术详解

文章目录 1. Filter 过滤器1.1 Filter 概述1.2 Filter 快速入门开发步骤:1.3 Filter 执行流程1.4 Filter 拦截路径配置1.5 过滤器链2. Listener 监听器2.1 Listener 概述2.2 ServletContextListener3. Ajax 技术3.1 Ajax 概述3.2 Ajax 快速入门服务端实现:客户端实现:4. Axi…...

生产管理系统开发:专业软件开发公司的实践与思考

生产管理系统开发的关键点 在当前制造业智能化升级的转型背景下&#xff0c;生产管理系统开发正逐步成为企业优化生产流程的重要技术手段。不同行业、不同规模的企业在推进生产管理数字化转型过程中&#xff0c;面临的挑战存在显著差异。本文结合具体实践案例&#xff0c;分析…...

前端异步编程全场景解读

前端异步编程是现代Web开发的核心&#xff0c;它解决了浏览器单线程执行带来的UI阻塞问题。以下从多个维度进行深度解析&#xff1a; 一、异步编程的核心概念 JavaScript的执行环境是单线程的&#xff0c;这意味着在同一时间只能执行一个任务。为了不阻塞主线程&#xff0c;J…...