C#浅拷贝和深拷贝数据

目录

一、浅拷贝

二、深拷贝


一、浅拷贝

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

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

1.建立项目

2.建立树结构数据

cs 复制代码
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

效果一样,代码如下:

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

3.表达式树

和上面的效果一样。

4.AutoMapper

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

此时我们需要先安装

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

可见,效果都是一样的。

代码:

cs 复制代码
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博客

相关推荐
码老白几秒前
【老白学 Java】Warshipv2.0(二)
java·网络
苹果酱05671 分钟前
前端面试vue篇:Vue2 和 Vue3 在设计和性能上有显著区别
java·spring boot·毕业设计·layui·课程设计
万琛13 分钟前
【java-Neo4j 5开发入门篇】-最新Java开发Neo4j
java·neo4j
Bald Baby31 分钟前
JWT的使用
java·笔记·学习·servlet
魔道不误砍柴功37 分钟前
实际开发中的协变与逆变案例:数据处理流水线
java·开发语言
鲤籽鲲1 小时前
C# MethodTimer.Fody 使用详解
开发语言·c#·mfc
dj24429457071 小时前
JAVA中的Lamda表达式
java·开发语言
工业3D_大熊1 小时前
3D可视化引擎HOOPS Luminate场景图详解:形状的创建、销毁与管理
java·c++·3d·docker·c#·制造·数据可视化
szc17671 小时前
docker 相关命令
java·docker·jenkins