温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C#深拷贝的方法是什么

发布时间:2022-04-16 13:35:56 来源:亿速云 阅读:163 作者:iii 栏目:开发技术

今天小编给大家分享一下C#深拷贝的方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

测试平台:Intel 9700K+DDR4 3600 32G,框架为.NET 5.0。测试方式为创建100万次,比较执行时间。拷贝的对象如下:

[Serializable] class UserInfo     {         public string Name { get; set; }         public string UserId { get; set; }         public int Age { get; set; }         public string Address { get; set; }         public long UpdateTime { get; set; }         public long CreateTime { get; set; }     }

1、手写创建对象

简单对象创建,不考虑有构造函数的情况。

NewUserInfo newInfo = new NewUserInfo() {     Name = info.Name,     Age = info.Age,     UserId = info.UserId,     Address = info.Address,     UpdateTime = info.UpdateTime,     CreateTime = info.CreateTime, };

100万次执行时间为39.4073ms,位居第一。当然,在这种不考虑构造函数的情况下,手写创建肯定是最快的。但是同时,如果遇到复杂对象,代码量也是最多的。

2、反射

这也是在日常代码中最常用的方式之一。

private static TOut TransReflection<TIn, TOut>(TIn tIn) {     TOut tOut = Activator.CreateInstance<TOut>();     var tInType = tIn.GetType();     foreach (var itemOut in tOut.GetType().GetProperties())     {         var itemIn = tInType.GetProperty(itemOut.Name); ;         if (itemIn != null)         {             itemOut.SetValue(tOut, itemIn.GetValue(tIn));         }     }     return tOut; }

调用

NewUserInfo newInfo = TransReflection<UserInfo, NewUserInfo>(info);

100万次执行时间为1618.4662ms,平均执行时间为0.001618,看起来还行。

3、Json字符串序列化

使用System.Text.Json作为序列化和反序列化工具。

UserInfo newInfo = JsonSerializer.Deserialize<UserInfo>(JsonSerializer.Serialize(info));

100万次执行时间为2222.2078ms,比反射慢一点点。

4、对象二进制序列化

首先不推荐使用这种方式,一是BinaryFormatter.Serialize微软已不推荐使用(据微软官网文档说是有漏洞,具体有什么漏洞没细究),二是必须在要序列化的对象上面写上Serializable的关键字,三是速度并不理想。

private static TOut ObjectMemoryConvert<TIn, TOut>(TIn tIn) {     using (MemoryStream ms = new MemoryStream())     {         BinaryFormatter formatter = new BinaryFormatter();         formatter.Serialize(ms, tIn);         ms.Position = 0;         return (TOut)formatter.Deserialize(ms);     } }

100万次执行时间为8545.9835ms,讲道理应该是比Json序列化要更快的,但是实际上慢了许多。

5、AutoMapper

熟悉的AutoMapper,性能也没有让我们失望。

//循环外创建MapperConfig var config = new MapperConfiguration(cfg => cfg.CreateMap<UserInfo, UserInfo>()); var mapper = config.CreateMapper(); //循环内调用 UserInfo newInfo = mapper.Map<UserInfo>(info);

100万次执行时间为267.5073ms,位居第三。

6、表达式树

重头戏来了,此处代码来源于文首中的博客中,性能让人大吃一惊。其原理是反射和表达式树相结合,先用反射获取字段然后缓存起来,再用表达式树赋值。

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);     } }

调用

UserInfo newInfo = TransExp<UserInfo, UserInfo>.Trans(info);

100万次执行时间为77.3653ms,位居第二。仅比手写慢一点点。

简单整理成柱状图,可以很清晰的对比出这几种深拷贝方式之间的速度差距。总结来说就是,一般简单的对象深拷贝,推荐直接手写,复杂对象深拷贝,推荐使用表达式树。当然,如果创建对象中还涉及到构造函数初始化,那又是不同的情况,这里暂不讨论。

C#深拷贝的方法是什么

附上本次测试用的完整代码。

using AutoMapper; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq.Expressions; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text.Json; using System.Threading.Tasks; namespace TestObjectDeepCopy {     class Program     {         static void Main(string[] args)         {             UserInfo info = new UserInfo()             {                 Name = "张三",                 Age = 18,                 UserId = Guid.NewGuid().ToString("N"),                 Address = "银河系地球中国",                 UpdateTime = 1615888888,                 CreateTime = 1615895454,             };             var config = new MapperConfiguration(cfg => cfg.CreateMap<UserInfo, UserInfo>());             var mapper = config.CreateMapper();             int count = 1000000;             Stopwatch sw = new Stopwatch();             sw.Start();             for (int i = -0; i < count; i++)             {                 //手写 39.4073ms                 //UserInfo newInfo = new UserInfo()                 //{                 //    Name = info.Name,                 //    Age = info.Age,                 //    UserId = info.UserId,                 //    Address = info.Address,                 //    UpdateTime = info.UpdateTime,                 //    CreateTime = info.CreateTime,                 //};                 //反射 1618.4662ms                 //UserInfo newInfo = TransReflection<UserInfo, UserInfo>(info);                 //Json字符串序列化 2222.2078ms                 //UserInfo newInfo = JsonSerializer.Deserialize<UserInfo>(JsonSerializer.Serialize(info));                 //对象二进制序列化 8545.9835ms                 //UserInfo newInfo = ObjectMemoryConvert<UserInfo, UserInfo>(info);                 //表达式树 77.3653ms                 //UserInfo newInfo = TransExp<UserInfo, UserInfo>.Trans(info);                 //AutoMapper 267.5073ms                 //UserInfo newInfo = mapper.Map<UserInfo>(info);             }             Console.WriteLine("总共花费{0}ms.", sw.Elapsed.TotalMilliseconds);             sw.Stop();             Console.ReadKey();         }         private static TOut TransReflection<TIn, TOut>(TIn tIn)         {             TOut tOut = Activator.CreateInstance<TOut>();             var tInType = tIn.GetType();             foreach (var itemOut in tOut.GetType().GetProperties())             {                 var itemIn = tInType.GetProperty(itemOut.Name); ;                 if (itemIn != null)                 {                     itemOut.SetValue(tOut, itemIn.GetValue(tIn));                 }             }             return tOut;         }         private static TOut ObjectMemoryConvert<TIn, TOut>(TIn tIn)         {             using (MemoryStream ms = new MemoryStream())             {                 BinaryFormatter formatter = new BinaryFormatter();                 formatter.Serialize(ms, tIn);                 ms.Position = 0;                 return (TOut)formatter.Deserialize(ms);             }         }     }     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);         }     }     [Serializable]     class UserInfo     {         public string Name { get; set; }         public string UserId { get; set; }         public int Age { get; set; }         public string Address { get; set; }         public long UpdateTime { get; set; }         public long CreateTime { get; set; }     } }

以上就是“C#深拷贝的方法是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI