.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.mfbz.cn/a/498089.html

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

相关文章

【测试开发学习历程】Python数据类型:字符串-str(上)

目录 1 Python中的引号 2 字符串的声明 3 字符串的切片 4 字符串的常用函数 4.1 len()函数 4.2 ord()函数 4.3 chr()函数 5 字符串的常用方法&#xff08;内置方法/内建方法&#xff09; 5.1 find()方法 5.2 index()方法 5.3 rfind()方法 5.4 rindex()方法 1 Python…

每日一练:LeeCode-48、旋转图像【二维数组+行列交换】

给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出…

免费软件“蓝莓投屏”:支持多个Airplay同时镜像的投屏软件。

引言&#xff1a; 由于定制盒子(3288)不支持投屏功能&#xff08;有些5.1不支持&#xff0c;安卓4.X本身也不支持&#xff09;&#xff0c;需要借助第三方的投屏软件来实现这一需求。所以&#xff0c;研究半天&#xff0c;蓝莓投屏以其简便易用的特性脱颖而出&#xff0c;只需…

imbalanced-learn,一个强大的 Python 库!

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个强大的 Python 库 - imbalanced-learn Github地址&#xff1a;https://github.com/scikit-learn-contrib/imbalanced-learn 在实际的数据分析和机器学习任务中&#xff0c;经常会遇到数据不平…

植物大战僵尸Javascript版web游戏源码

源码介绍 植物大战僵尸Javascript版web游戏源码&#xff0c;非常强大&#xff0c;1比1还原电脑版植物大战僵尸游戏&#xff0c;带背景音乐&#xff0c;玩法和原版一模一样。 源码截图 下载地址 https://download.csdn.net/download/huayula/89048275

基于微信小程序的民宿短租系统设计与实现(论文+源码)_kaic

摘 要 随着社会的发展&#xff0c;出差、旅游成为常态&#xff0c;也就造成民宿短租市场的兴起。人们新到陌生的环境里找民宿一般都是通过中介。中介虽然可以快速找到合适的民宿但会收取大量的中介费用&#xff0c;这对刚到新环境里的人们来说是一笔大的资金支出。也有一些人通…

Linux内核之最核心数据结构之二:struct inode(三十一)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

k8s局域网通过operator部署rabbitmq

参考&#xff1a;Installing RabbitMQ Cluster Operator in a Kubernetes Cluster | RabbitMQ 1、下载cluster-operator.yml wget https://github.com/rabbitmq/cluster-operator/releases/download/v2.7.0/cluster-operator.yml 2、拉取对应的镜像&#xff0c;这里的版本是根…

springboot+vue在idea上面的使用小结

1.在mac上面删除java的jdk方法&#xff1a; sudo rm -rfjdk的路径 sudo rm -rf /Users/like/Library/Java/JavaVirtualMachines/corretto-17.0.10/Contents/Home 2.查询 Mac的jdk版本和路径&#xff1a; /usr/libexec/java_home -V 3.mac上面查询和关闭idea的网页端口&…

|行业洞察·汽车|《新能源汽车行业发展及营销策略分析-35页》

报告的主要内容解读&#xff1a; 行业环境&#xff1a;报告指出&#xff0c;海外车企的电动化进程遇到阻碍&#xff0c;而中国新能源汽车市场持续增长&#xff0c;2023年销量占全球新能源汽车的63.5%&#xff0c;市占率达到31.6%。 市场政策&#xff1a;中国政府通过减免税收、…

GT收发器第一篇_总体结构介绍

文章目录 前言GT收发器介绍 前言 之前写过一篇简单介绍GT的文章https://blog.csdn.net/m0_56222647/article/details/136730026&#xff0c;可以先通过这篇文章对整体进行简单了解一下。 GT收发器介绍 参考xilinx手册ug476 对于7系列的FPGA&#xff0c;共有3个系列&#xf…

JAVAEE——线程池

文章目录 线程池的概念什么是线程池&#xff1f; 标准库中的线程池线程池的创建工厂模式工厂模式的用途线程池涉及到的类有哪些Executor接口ExecutorService接口Executors工厂类AbstractExecutorService虚类ThreadPoolExecutor普通类ThreadPoolExecutor内部的实现4个拒绝策略 线…

【MySQL】6.MySQL主从复制和读写分离

主从复制 主从复制与读写分离 通常数据库的读/写都在同一个数据库服务器中进行&#xff1b; 但这样在安全性、高可用性和高并发等各个方面无法满足生产环境的实际需求&#xff1b; 因此&#xff0c;通过主从复制的方式同步数据&#xff0c;再通过读写分离提升数据库的并发负载…

【微服务】Nacos(配置中心)

文章目录 1.AP和CP1.基本介绍2.说明 2.Nacos配置中心实例1.架构图2.在Nacos Server加入配置1.配置列表&#xff0c;加号2.加入配置3.点击发布&#xff0c;然后返回4.还可以编辑 3. 创建 Nacos 配置客户端模块获取配置中心信息1.创建子模块 e-commerce-nacos-config-client50002…

快速编译嵌入式Linux(4.9.229)内核(硬件:mini2440)

目录 概述 1 Linux内核介绍 1.1 Linux 内核版本 1.2 下载Linux 内核 2 编译内核 2.1 解压内核 2.2 编译环境 2.3 编译内核 概述 本文主要以硬件板卡mini2440为例&#xff0c;介绍如何从linux内核官网下载一个原生态的内核源码包&#xff0c;通过简单的配置编译适合在AR…

誉天华为认证云计算课程如何

HCIA-Cloud Computing 5.0 课程介绍&#xff1a;掌握华为企业级虚拟化、桌面云部署&#xff0c;具备企业一线部署实施及运维能力 掌握虚拟化技术、网络基础、存储基础等内容&#xff0c;拥有项目实施综合能力 满足企业虚拟化方案转型需求&#xff0c;应对企业日益多样的业务诉求…

excel中批量插入分页符

excel中批量插入分页符&#xff0c;实现按班级打印学生名单。 1、把学生按照学号、班级排序好。 2、选择班级一列&#xff0c;点击数据-分类汇总。汇总方式选择计数&#xff0c;最后三个全部勾选。汇总结果一定要显示在数据的下发&#xff0c;如果显示在上方&#xff0c;后期…

typescript 实现RabbitMQ死信队列和延迟队列 订单10分钟未付归还库存

Manjaro安装RabbitMQ 安装 sudo pacman -S rabbitmq rabbitmqadmin启动管理模块 sudo rabbitmq-plugins enable rabbitmq_managementsudo rabbitmq-server管理界面 http://127.0.0.1:15672/ 默认用户名和密码都是guest。 要使用 rabbitmqctl 命令添加用户并分配权限&#xf…

RTOS线程切换的过程和原理

0 前言 RTOS中最重要的一个概念就是线程&#xff0c;线程的按需切换能够满足RTOS的实时性要求&#xff0c;同时能将复杂的需求分解成一个个线程执行减轻我们开发负担。 本文从栈的角度出发&#xff0c;详细介绍RTOS线程切换的过程和原理。 注&#xff1a;本文参考的RTOS是RT-T…

Typora字数过多的时候造成卡顿现象如何解决?

Typora字数过多的时候造成卡顿现象如何解决&#xff1f; 点击 、切换、滚动、打字都有点卡顿&#xff0c;下面介绍三种方法&#xff0c;三种方法都可以尝试&#xff0c;建议先尝试方法一&#xff0c;效果不满意就用方法二&#xff0c;实在不行就最后一个取巧的办法。 方法1&a…