C#浅拷贝和深拷贝数据

目录

一、浅拷贝

二、深拷贝


一、浅拷贝

就是把原来的数据,复制一份,但是2份数据共享地址的,修改第一份数据或者修改第二份数据,都会一起改变,这可能不是我们程序中需要的场景。

下面我们演示一下,首先建立一个树结构的数据类型,其他类型也可以

1.建立项目

2.建立树结构数据

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfApp4
{
    public class TestData1
    {
        public int ID { get; set; }
        public string D1 { get; set; }
        public string D2 { get; set; }

        public TestData2 testData2 { get; set; }
    }

    public class TestData2
    {
        public int ID { get; set; }
        public string D1 { get; set; }
        public string D2 { get; set; }

        public TestData3 testData3 { get; set; }
    }

    public class TestData3
    {
        public int ID { get; set; }
        public string D1 { get; set; }
        public string D2 { get; set; }
    }
}

2.效果

此时testData1的值,呈现树结构显示

把testData1的值赋值给test1后,依然呈现树结构显示

当修改testData1的D1的值后,test1的D1的值也改变了

这个就是浅拷贝,这种拷贝在程序场景中很少用到,不知道的人,偶尔会很奇怪。

二、深拷贝

就是把原来的数据,复制一份,但是2份数据不是共享地址的,修改第一份数据或者修改第二份数据,不会一起改变,这种场景大部分是我们程序中需要的场景。

前面的数据结构依然不变,深拷贝在程序中运用的场景非常多,我们说4种方法。

1.反射实现

可见,修改testData1的D1的值后,test2的D1的值,并没有变化,这正是我们需要的,后续可以对testData1和test2的数据,分别进行业务操作。 

2.JSON字符串序列化

此处需要使用Newtonsoft.Json这个包

这里我们首先是先把对象转成字符串,再把字符串转成对象,效果和上面是一样的。 

补充:也可以使用Net6中自带的序列化,需要引用System.Text.Json

效果一样,代码如下:

           var test31 = JsonSerializer.Deserialize<TestData1>(JsonSerializer.Serialize(testData1));   //首先是先把对象转成字符串,再把字符串转成对象
            testData1.D1 = "我修改了";

3.表达式树

和上面的效果一样。

4.AutoMapper

这个是第三方的,也可以使用其他的对象映射

此时我们需要先安装

安装完成后,第一句代码,需要进行配置,然后直接调用即可 

可见,效果都是一样的。 

代码:


using AutoMapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using static WpfApp4.MainWindow;
using Expression = System.Linq.Expressions.Expression;

namespace WpfApp4
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            TestData3 testData3 = new TestData3();
            testData3.ID = 3;
            testData3.D1 = "3.1";
            testData3.D2 = "3.2";

            TestData2 testData2 = new TestData2();
            testData2.ID = 2;
            testData2.D1 = "2.1";
            testData2.D2 = "2.2";
            testData2.testData3 = testData3;

            TestData1 testData1 = new TestData1();
            testData1.ID = 1;
            testData1.D1 = "1.1";
            testData1.D2 = "1.2";
            testData1.testData2 = testData2;

            #region 浅拷贝演示
            浅拷贝演示,把testData1复制一份
            //TestData1 test1 = testData1;
            修改test1的值,那么testData1的值也会变化
            //testData1.D1 = "我修改了";
            #endregion

            #region 深拷贝演示
            //1.反射
            //var test2 = DeepCopyWithReflection(testData1);
            //testData1.D1 = "我修改了";
            //2.JSON字符串序列化
            //var test3 = JsonConvert.DeserializeObject<TestData1>(JsonConvert.SerializeObject(testData1));   //首先是先把对象转成字符串,再把字符串转成对象
            //testData1.D1 = "我修改了";

            //var test31 = JsonSerializer.Deserialize<TestData1>(JsonSerializer.Serialize(testData1));   //首先是先把对象转成字符串,再把字符串转成对象
            //testData1.D1 = "我修改了";
            //3.表达式树
            //var test4 = TransExp<TestData1, TestData1>.Trans(testData1);
            //testData1.D1 = "我修改了";

            //4.AutoMapper
            var config = new MapperConfiguration(cfg => cfg.CreateMap<TestData1, TestData1>());//映射配置
            var test5 = config.CreateMapper().Map<TestData1>(testData1);
            testData1.D1 = "我修改了";
            #endregion

        }



        /// <summary>
        /// 利用反射实现深拷贝
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T DeepCopyWithReflection<T>(T obj)
        {
            Type type = obj.GetType();

            // 如果是字符串或值类型则直接返回
            if (obj is string || type.IsValueType) return obj;
            // 如果是数组
            if (type.IsArray)
            {
                Type elementType = Type.GetType(type.FullName.Replace("[]", string.Empty));
                var array = obj as Array;
                Array copied = Array.CreateInstance(elementType, array.Length);
                for (int i = 0; i < array.Length; i++)
                {
                    copied.SetValue(DeepCopyWithReflection(array.GetValue(i)), i);
                }
                return (T)Convert.ChangeType(copied, obj.GetType());
            }

            object retval = Activator.CreateInstance(obj.GetType());

            PropertyInfo[] properties = obj.GetType().GetProperties(
                BindingFlags.Public | BindingFlags.NonPublic
                | BindingFlags.Instance | BindingFlags.Static);
            foreach (var property in properties)
            {
                var propertyValue = property.GetValue(obj, null);
                if (propertyValue == null)
                    continue;
                property.SetValue(retval, DeepCopyWithReflection(propertyValue), null);
            }

            return (T)retval;
        }
        /// <summary>
        /// 表达式树
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        public static class TransExp<TIn, TOut>
        {
            private static readonly Func<TIn, TOut> cache = GetFunc();
            private static Func<TIn, TOut> GetFunc()
            {
                ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
                List<MemberBinding> memberBindingList = new List<MemberBinding>();

                foreach (var item in typeof(TOut).GetProperties())
                {
                    if (!item.CanWrite) continue;
                    MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }

                MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
                Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] { parameterExpression });

                return lambda.Compile();
            }

            public static TOut Trans(TIn tIn)
            {
                return cache(tIn);
            }

        }

    }
}

本案例代码:

https://download.csdn.net/download/u012563853/88637534

来源:

C#浅拷贝和深拷贝数据-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/252296.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

时序预测 | Python实现GRU电力需求预测

时序预测 | Python实现GRU电力需求预测 目录 时序预测 | Python实现GRU电力需求预测预测效果基本描述程序设计参考资料预测效果 基本描述 该数据集因其每小时的用电量数据以及 TSO 对消耗和定价的相应预测而值得注意,从而可以将预期预测与当前最先进的行业预测进行比较。使用该…

MySql的增、删、改、查(MySql数据库学习——五)

增&#xff08;数据添加/插入数据&#xff09; 使用 INSERT INTO SQL 语句来插入数据。我们可以通过 mysql> 命令提示窗口中向数据表中插入数据&#xff0c;或者 通过PHP 脚本来插入数据。 sql语句&#xff1a; INSERT INTO table_name ( field1, field2,...fieldN ) …

暂退法(丢弃法)

在深度学习中&#xff0c;丢弃法&#xff08;Dropout&#xff09;是一种常用的正则化技术&#xff0c;旨在减少模型的过拟合现象&#xff0c;可能会比之前的权重衰减(Weight Decay)效果更好。通过在训练过程中随机丢弃一部分神经元&#xff0c;可以有效地减少神经网络中的参数依…

【华为数据之道学习笔记】5-4 数据入湖方式

数据入湖遵循华为信息架构&#xff0c;以逻辑数据实体为粒度入湖&#xff0c;逻辑数据实体在首次入湖时应该考虑信息的完整性。原则上&#xff0c;一个逻辑数据实体的所有属性应该一次性进湖&#xff0c;避免一个逻辑实体多次入湖&#xff0c;增加入湖工作量。 数据入湖的方式…

如何从 iPhone 上恢复已删除的照片教程分享

您是否错误地删除了 iPhone 上的错误照片&#xff1f;或者您可能已将手机恢复出厂设置&#xff0c;但现在所有照片都消失了&#xff1f;如果您现在遇到这样的情况&#xff0c;我们可以为您提供解决方案。 在本文中&#xff0c;我们将向您展示七种数据恢复方法&#xff0c;可以…

对可恢复的情况使用受检异常

在Java中&#xff0c;受检异常&#xff08;Checked Exception&#xff09;通常用于表示程序能够预期并且可能进行恢复的异常情况。这类异常是在编译时由编译器强制进行处理的&#xff0c;使得程序员必须显式处理这些异常&#xff0c;或者在方法签名中使用 throws 关键字声明。 …

Zoho Mail企业邮箱:6大高效使用技巧

本期小Z就带您了解下&#xff0c;Zoho Mail非常实用的几个小技巧&#xff0c;帮助您进一步提升工作效率。 01/轻松从其他邮箱迁移到Zoho Mail 每天我们都会收到很多垃圾邮件、网络钓鱼、或者不需要的促销邮件等等&#xff0c;筛选出这些邮件耗时耗力&#xff0c;这个时候寻找…

借着期末作业,写一个JavaWeb项目

合集传送门 要求 学生成绩管理系统设计与实现 设计一个学生成绩管理系统。根据以下功能&#xff0c;分析使用的逻辑结构和存储结构。并设计菜单&#xff0c;显示相应结果。 &#xff08;1&#xff09;录入功能&#xff1a;能够录入学生成绩&#xff08;包括&#xff1a;学号…

面向对象方法分析之 各种图

没想到研究生了还要跟这些奇奇怪怪的图打交道&#xff08;不是&#xff09; 以下是面向对象分析中常用到的图。 静态视图 静态视图对应用领域中的概念以及与系统实现有关的内部概念建模&#xff0c;主要由类以及类之间的相互关系组成&#xff0c;在静态视图中不描述依赖于时…

《opencv实用探索·二十》点追踪技术

前言&#xff1a; 在学习点追踪技术前需要先了解下光流发追踪目标&#xff0c;可以看上一章内容&#xff1a;光流法检测运动目标 如果以光流的方式追踪目标&#xff0c;基本上我们可以通过goodFeaturesToTrack函数计算一系列特征点&#xff0c;然后通过Lucas-Kanade算法进行一…

vue3 setup语法糖写法基本教程

前言 官网地址&#xff1a;Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org)下面只讲Vue3与Vue2有差异的地方&#xff0c;一些相同的地方我会忽略或者一笔带过与Vue3一同出来的还有Vite&#xff0c;但是现在不使用它&#xff0c;等以后会有单独的教程使用。目前仍旧使用v…

XXE漏洞 [NCTF2019]Fake XML cookbook1

打开题目 查看源代码 发现我们post传入的数据都被放到了doLogin.php下面 访问一下看看 提示加载外部xml实体 bp抓包一下看看 得到flag 或者这样 但是很明显这样是不行的&#xff0c;因为资源是在admin上&#xff0c;也就是用户名那里 PHP引用外部实体&#xff0c;常见的利用…

Explain工具-SQL性能优化

文章目录 SQL性能优化的目标Explain中type效率级别&#xff08;重要&#xff09;注意 Explain覆盖索引ExplainindexExplainfilesortExplainfilesort创建 idx_bd(b,d) SQL性能优化的目标 达到 range 级别 Explain中type效率级别&#xff08;重要&#xff09; 显示的是单位查询…

Ubuntu系统入门指南:基础操作和使用

Ubuntu系统的基础操作和使用 一、引言二、安装Ubuntu系统三、Ubuntu系统的基础操作3.1、界面介绍3.2、应用程序的安装和卸载3.3、文件管理3.4、系统设置 四、Ubuntu系统的日常使用4.1、使用软件中心4.2、浏览器的使用和网络连接设置4.3、邮件客户端的配置和使用4.4、文件备份和…

【上海大学数字逻辑实验报告】七、中规模元件及综合设计

一、实验目的 掌握中规模时序元件的测试。学会在Quartus II上设计序列发生器。 二、实验原理 74LS161是四位可预置数二进制加计数器&#xff0c;采用16引脚双列直插式封装的中规模集成电路&#xff0c;其外形如下图所示&#xff1a; 其各引脚功能为&#xff1a; 异步复位输…

我的世界指令大全

不知道我的世界指令大全&#xff1f;我的世界玩家我的世界指令大全&#xff0c;在下面的攻略中就为小伙伴们带来了我的世界指令大全。不知道我的世界指令大全的玩家们那就继续看下去这篇攻略吧。 1./summon&#xff1a;召唤实体。 2./give&#xff1a;给予玩家物品。 3./tp&a…

Epic 安装失败,错误代码SUPQR1612,必要的先决条件安装失败,弹窗CD-ROM

错误记录 并且弹出来这个窗口the feature you are trying to use is on a CD-ROM or other removable disk that is not available. 让我寻找这个msi文件 正在想办法解决 如果有人能解决 麻烦告知评论区&#xff01;

Nginx编译安装+Nginx模块详解+Nginx虚拟主机(新版)

Nginx编译安装Nginx模块详解Nginx虚拟主机 Nginx编译安装Nginx模块详解Nginx虚拟主机一、编译安装Nginx服务二、nginx版本升级1、nginx平滑升级的步骤2、示例 三、添加Nginx系统服务1、使用init.d脚本2、使用 systemd 服务配置 四、认识Nginx服务的主配置文件 nginx.conf1、全局…

为什么Apache Doris适合做大数据的复杂计算,MySQL不适合?

为什么Apache Doris适合做大数据的复杂计算&#xff0c;MySQL不适合&#xff1f; 一、背景说明二、DB架构差异三、数据结构差异四、存储结构差异五、总结 一、背景说明 经常有小伙伴发出这类直击灵魂的疑问&#xff1a; Q&#xff1a;“为什么Apache Doris适合做大数据的复杂计…

819. 最常见的单词

819. 最常见的单词 Java&#xff1a;split() 过滤 class Solution {public String mostCommonWord(String paragraph, String[] banned) {String s paragraph.replaceAll("\\p{Punct}", " "); // 去除所有标点符号String arr[] s.split(" "…