.Net 对象与对象之间的映射转换的6中方式以及性能对比

我们在.Net开发的过程中,经常会遇到一个实体对象与另一个实体对象之间的映射转换,接下来我们将依次去实现6个对象间映射转换的方式,并对他们进行性能测试,找出其中效率最高的方式。

  1. 通过对象Copy,通过new一个新的实体对象通过手动赋值的方式实现

    public class ObjectCopyMapper
    {/// <summary>/// 第一种就是通过New一个目标对象给所有属性手动赋值/// </summary>public static UserModel Trans(User userEntry){return new UserModel(){Id = userEntry.Id,UserName = userEntry.UserName,NickName = userEntry.NickName,};}
    }

  2. 通过反射依次找出目标实体对象中需要的属性和字段,再从源实体对象中获取到对应属性和字段的值

     public class ReflectionMapper{/// <summary>/// 通过反射的方式实现对象之间的映射/// </summary>/// <typeparam name="TIn"></typeparam>/// <typeparam name="TOut"></typeparam>/// <param name="tIn"></param>/// <returns></returns>public static TOut Trans<TIn, TOut>(TIn tIn){TOut tOut = Activator.CreateInstance<TOut>();foreach (var itemOut in tOut.GetType().GetProperties()){var propIn = tIn.GetType().GetProperty(itemOut.Name);itemOut.SetValue(tOut, propIn.GetValue(tIn));}foreach (var itemOut in tOut.GetType().GetFields()){var fieldIn = tIn.GetType().GetField(itemOut.Name);itemOut.SetValue(tOut, fieldIn.GetValue(tIn));}return tOut;}}

  3. 通过Json序列化反序列化的方式实现,这种是最简单的

    public class SerializeMapper
    {/// <summary>/// 通过json序列化反序列化的方式实现/// </summary>/// <typeparam name="TIn"></typeparam>/// <typeparam name="TOut"></typeparam>/// <param name="tIn"></param>/// <returns></returns>public static TOut Trans<TIn, TOut>(TIn tIn){return JsonConvert.DeserializeObject<TOut>(JsonConvert.SerializeObject(tIn));}
    }

  4. 通过表达式目录树解析并缓存在字典中

     public class ExpressionMapper{private static Dictionary<string, object> dics = new Dictionary<string, object>();/// <summary>/// 采用字典缓存表达式树实现/// </summary>/// <typeparam name="TIn"></typeparam>/// <typeparam name="TOut"></typeparam>/// <param name="tIn"></param>/// <returns></returns>public static TOut Trans<TIn, TOut>(TIn tIn){string key = $"funckey_{typeof(TIn).FullName}_{typeof(TOut).FullName}";if (!dics.ContainsKey(key)){ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");List<MemberBinding> memberBindings = new List<MemberBinding>();foreach(var item in typeof(TOut).GetProperties()){MemberExpression memberExpression = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));MemberBinding memberBinding = Expression.Bind(item, memberExpression);memberBindings.Add(memberBinding);}foreach (var item in typeof(TOut).GetFields()){MemberExpression memberExpression = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));MemberBinding memberBinding = Expression.Bind(item, memberExpression);memberBindings.Add(memberBinding);}MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindings.ToArray());Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] { parameterExpression});Func<TIn, TOut> func = lambda.Compile();//只拼装一次dics[key] = func;}return ((Func<TIn, TOut>)dics[key]).Invoke(tIn);}}

  5. 通过表示是目录树解析并应用泛型缓存

     /// <summary>/// 采用泛型缓存表达式目录树实现/// </summary>/// <typeparam name="TIn"></typeparam>/// <typeparam name="TOut"></typeparam>public class ExpressionGenericMapper<TIn, TOut>{private static Func<TIn, TOut> _FUNC = null;static ExpressionGenericMapper(){ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");List<MemberBinding> memberBindingList = new List<MemberBinding>();foreach (var item in typeof(TOut).GetProperties()){MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));MemberBinding memberBinding = Expression.Bind(item, property);memberBindingList.Add(memberBinding);}foreach (var item in typeof(TOut).GetFields()){MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(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});_FUNC = lambda.Compile();//拼装是一次性的}public static TOut Trans(TIn t){return _FUNC(t);}}

  6. 通过AutoMapper库实现

    var configuration = new MapperConfiguration(cfg =>
    {cfg.CreateMap<User, UserModel>();
    });
    configuration.AssertConfigurationIsValid();
    var mapper = configuration.CreateMapper();
    UserModel dest = mapper.Map<UserModel>(user);

  7. 性能测试,我们进行100W次映射转换,统计各种方式需要的执行时间

    User user = new User() { Id = 1,UserName = "Test",NickName = "测试用户",
    };long commonTime = 0;
    Stopwatch watch = new Stopwatch();
    watch.Start();
    {for (int i = 0; i < 1_000_000; i++){ObjectCopyMapper.Trans(user);}watch.Stop();commonTime = watch.ElapsedMilliseconds;Console.WriteLine($"ObjectCopyMapper 用时:{commonTime}ms");
    }{watch.Restart();for (int i = 0; i < 1_000_000; i++){ReflectionMapper.Trans<User, UserModel>(user);}watch.Stop();commonTime = watch.ElapsedMilliseconds;Console.WriteLine($"ReflectionMapper 用时:{commonTime}ms");
    }{watch.Restart();for (int i = 0; i < 1_000_000; i++){SerializeMapper.Trans<User, UserModel>(user);}watch.Stop();commonTime = watch.ElapsedMilliseconds;Console.WriteLine($"SerializeMapper 用时:{commonTime}ms");
    }{watch.Restart();for (int i = 0; i < 1_000_000; i++){ExpressionMapper.Trans<User, UserModel>(user);}watch.Stop();commonTime = watch.ElapsedMilliseconds;Console.WriteLine($"ExpressionMapper 用时:{commonTime}ms");
    }{watch.Restart();for (int i = 0; i < 1_000_000; i++){UserModel model = ExpressionGenericMapper<User, UserModel>.Trans(user);}watch.Stop();commonTime = watch.ElapsedMilliseconds;Console.WriteLine($"ExpressionGenericMapper 用时:{commonTime}ms");
    }{watch.Restart();var configuration = new MapperConfiguration(cfg =>{cfg.CreateMap<User, UserModel>();});configuration.AssertConfigurationIsValid();var mapper = configuration.CreateMapper();for (int i = 0; i < 1_000_000; i++){UserModel dest = mapper.Map<UserModel>(user);}watch.Stop();commonTime = watch.ElapsedMilliseconds;Console.WriteLine($"AutoMapper 用时:{commonTime}ms");
    }

    测试结果:

        ObjectCopyMapper 用时:52ms
        ReflectionMapper 用时:892ms
        SerializeMapper 用时:3468ms
        ExpressionMapper 用时:203ms
        ExpressionGenericMapper 用时:35ms
        AutoMapper 用时:209ms

        根据上面的测试数据,可以发现用时最长的是我们Json序列化和反序列化,用时最短的是我们自己封装的表达式目录树用泛型缓存。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

el-table的复选框勾选整行变色

要实现el-table的复选框勾选整行变色&#xff0c;你可以使用element-ui提供的row-class-name属性结合scoped slot来完成。 首先&#xff0c;你需要为el-table组件添加 row-class-name 属性&#xff0c;并给它绑定一个方法。在这个方法中&#xff0c;你可以根据你的业务逻辑来判…

【C+ +】第一个C+ + 项目的创建及namespace命名空间解释C++中的输入输出

目录 1.创建第一个c项目 1.1项目创建 1.2 .cpp源文件建立 1.3 第一个c程序hello world对比c语言hello world 2.命名空间 2.1 C关键字 2.2 命名空间---解决c语言中的命名冲突 2.2.1 namespace命名空间用法 2.2.2 &#xff1a;&#xff1a; 预作用限定符 2.2.3 命名空间的嵌套…

【嵌入式智能产品开发实战】(七)—— 政安晨:通过ARM-Linux掌握基本技能【环境准备:树莓派】

目录 Raspberry Pi OS 下载系统镜像 使用SSH客户端登陆 升级更新 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 嵌入式智能产品开发实战 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正…

人工智能|深度学习——基于Xception实现戴口罩人脸表情识别

一、项目背景 近年来&#xff0c;随着人工智能技术的不断发展&#xff0c;人脸表情识别已经成为了计算机视觉领域中的重要研究方向之一。然而&#xff0c;在当前的疫情形势下&#xff0c;佩戴口罩已经成为了一项必要的防疫措施&#xff0c;但是佩戴口罩会遮挡住人脸的部分区域&…

c++ new int[10]()会进行初始化.

new int[10]()-CSDN博客 #include<iostream> using namespace std;int main() {int *p new int[10]();for(int i 0; i < 10; i){cout << p[i] << endl;}delete []p; } 会进行初始化.

换到idf 5.0版本后报错 jsmn could not be found

原因&#xff1a; idf5.0去掉了部分组件&#xff0c;包括jsmn&#xff0c;工程中adf又用到了这个组件&#xff0c;所以会报错。 解决办法&#xff1a; 升级adf到新版本即可。

docker导出导入镜像

docker导出镜像 查看要导出的镜像 docker images主要有两列 REPOSITORY TAG 导出命令 导出公式 docker save -o xxxx.tar REPOSITORY:TAG例子 docker save -o minio.tar minio/minio:latestminio/minio:latest可以使用image id代替&#xff0c;但是使用image id会导致导…

梯度:般在神经网络里面是一个batch清空一次梯度还是一个epoch清空一次梯度?

通常&#xff0c;在神经网络训练中&#xff0c;是在每个 mini-batch 处理完成后清空一次梯度&#xff0c;而不是在每个 epoch 结束后清空一次梯度。 这是因为在每个 mini-batch 中&#xff0c;模型参数的梯度是根据当前 mini-batch 的损失计算得到的&#xff0c;如果不在每个 …

能效监测终端为什么这么好用?

能效监测终端是一种现代管理工具&#xff0c;它在企业和机构的能源管理体系中起着核心的作用。这些监测设备能够精确掌握用电设备的功耗情况&#xff0c;为用户实现节能减排和成本控制提供了有效的技术支持。以下内容将具体解释为什么能效监测终端如此好用&#xff0c;并从多个…

风声 | “革命”启动,这里是量子的新起点——

非洲正站在量子技术变革的前沿。 尽管非洲的量子安全技术尚未达到其他地区的先进水平&#xff0c;但它被视为未来计算技术发展的关键要素。如《福布斯非洲》所述&#xff1a;“量子计算目前的发展阶段&#xff0c;可以比喻为20世纪60年代的传统计算技术水平。” 非洲拥有众多的…

收下这份地表最强参会指南,4月16日,玩转百度Create大会不迷路

欢迎来到英杰社区&#xff1a; https://bbs.csdn.net/topics/617804998 欢迎来到阿Q社区&#xff1a; https://bbs.csdn.net/topics/617897397 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff…

vulnhub之devguru靶场提权过程(vulnhub打靶日记)

一、环境搭建 VM版本&#xff1a;17.5.1 build-23298084 攻击机&#xff1a;Kali2024&#xff08;下载地址&#xff1a;https://www.kali.org/&#xff09; 靶机&#xff1a;vulnhub靶场Devguru&#xff08;下载地址&#xff1a;https://www.vulnhub.com/entry/devguru-1,62…

Spring Boot集成disruptor快速入门demo

1.disruptor介绍 什么是 Disruptor? Disruptor 是英国外汇交易公司 LMAX 开发的一个高性能的并发框架。可以认为是线程间通信的高效低延时的内存消息组件&#xff0c;它最大的特点是高性能。与 Kafka、RabbitMQ 用于服务间的消息队列不同&#xff0c;disruptor 一般用于一个 J…

C++——异常机制

目录 一&#xff0c;背景 1.1 C语言处理错误的方式 1.2 C异常概念 二&#xff0c;异常的使用 2.1 异常的简单使用 2.2 异常的匹配原则 2.3 异常抛对象 2.4 异常的重新抛出 2.5 异常安全 三&#xff0c;自定义异常体系 四&#xff0c;异常优缺点 4.1 优点 4.2 缺点 …

【爬虫框架Scrapy】02 Scrapy入门案例

接下来介绍一个简单的项目&#xff0c;完成一遍 Scrapy 抓取流程。通过这个过程&#xff0c;我们可以对 Scrapy 的基本用法和原理有大体了解。 1. 本节目标 本节要完成的任务如下。 创建一个 Scrapy 项目。 创建一个 Spider 来抓取站点和处理数据。 通过命令行将抓取的内容…

从零开始为香橙派orangepi zero 3移植主线linux——2.linux kernel

从零开始为香橙派orangepi zero 3移植主线linux——2.linux kernel 0.环境搭建补档NFS服务TFTP服务 一、linux kernel编译二、运行 0.环境搭建补档 linux kernel验证时&#xff0c;使用tftp服务从ubuntu主机下载启动更加方便&#xff0c;等到验证无误后再一次性烧写到tf卡。所以…

选择哪些即时通讯产品,提高企业内部沟通与协作?

随着移动互联网的飞速发展&#xff0c;即时通讯工具已经成为了企业内部沟通和协作的首选。无论是即时聊天、文件共享、在线会议、日程安排还是群组沟通&#xff0c;都能帮助企业提高工作效率和协同能力。本文将推荐一些国内较为常用的即时通讯产品&#xff0c;并以 Slcak 为例&…

基于java+SpringBoot+Vue的校园交友网站设计与实现

基于javaSpringBootVue的校园交友网站设计与实现 开发语言: Java 数据库: MySQL技术: SpringBoot MyBatis工具: IDEA/Eclipse、Navicat、Maven 系统展示 前台展示 后台展示 系统简介 整体功能包含&#xff1a; 校园交友网站是一个为在校师生提供一个交流互动、寻找朋友的…

vue3+ts 调用接口,数据显示

数据展示 &#xff08;例&#xff1a;展示医院等级数据&#xff0c;展示医院区域数据同理。&#xff09; 接口文档中&#xff0c;输入参数 测试一下接口&#xff0c;发请求 看是否能够拿到信息 获取接口&#xff0c;api/index.ts 中 /home/index.ts // 统一管理首页模块接口 i…

ansible-自动化工具

一、ansible概述 不是C/S架构&#xff0c;就是一种工具 1&#xff1a;linux自动化运维 编写程序实现运维自动化&#xff1a;shell python 工具模式自动化&#xff1a; ①OS Provisioning&#xff1a; RedHat satellite&#xff1b;PXE&#xff08;可实现dhcp和tftp&#…