隐藏

.NET001-实体类与实体DTO类转换的思考与实现

发布:2022/5/21 17:26:15作者:管理员 来源:本站 浏览次数:898

几种常见方式:

    硬编码方式:直接对实体DTO类进行赋值,效率最高,但可维护性差,通用性差。

    反射,动态获取属性,效率低。

    Json序列化,反序列化:使用Newtonsoft.Json通过JsonConvert.SerializeObject<SourceClass,DestinDTO>(sourceInstance)进行序列化,通过JsonConvert.DeserializeObject(sSourceClass)来实现,效率很低。

    使用AutoMapper映射类来实现,Mapper.Initialize初始化,Mapper.Map<SourceClass,DestinDTO>(sourceInstance) 效率高。

    静态缓存字典+表达式目录树实现:和AutoMapper类效率差不多。

    泛型缓存+表达式目录树实现:效率仅次于硬编码。

各种方式实现的代码: 作者:DotNet技术官 https://www.bilibili.com/read/cv14634988 出处:bilibili

using Newtonsoft.Json;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using System.Linq.Expressions;
using DynamicExpresso;
using Gremlin.Net.Process.Traversal;

namespace DTOExample {
    class Program {
        public static Dictionary<string, object> _Dictionary = new Dictionary<string, object>();

        static void Main(string[] args) {
            Student student = new Student() { Age = 24, ID = 1, Name = "Albert" };
            //FirstMethod 使用Newtonsoft.Json序列号反序列化  此种方法效率很低
            string sStudent = JsonConvert.SerializeObject(student); //先序列化为字符串
            StudentDTO studentDTO = JsonConvert.DeserializeObject<StudentDTO>(sStudent);//反序列化
            //SecondMethod 使用automapper映射 专属的类型映射工具,为ORM而生 效率高
            Mapper.Initialize(x => x.CreateMap<Student, StudentDTO>());
            StudentDTO studentDTO1 = Mapper.Map<Student, StudentDTO>(student);
            //不同名称的映射
            //Mapper.Initialize(config=> {
            //    config.CreateMap<Student, StudentDTO>().
            //    ForMember(dest => dest.DickName, options => options.MapFrom(sou => sou.Name));
            //});
            //StudentDTO studentDTO2 = Mapper.Map<Student, StudentDTO>(student);
            //ThirdMethod 表达式目录树+静态缓存字典

            //表达式目录树+静态字典
            StudentDTO studentDTO3 = Trans<Student, StudentDTO>(student);
            //效率较高,表达式目录树+泛型缓存
            StudentDTO studentDTO4 = ExpressionGenericMapper<Student, StudentDTO>.Trans(student);
        }

        //表达式+静态字典
        public static TOut Trans<TIn,TOut>(TIn tIn) {
            TOut tOut = Activator.CreateInstance<TOut>();
            string key = string.Format("funckey_{0}_{1}", tIn.GetType().Name, tOut.GetType().Name);
            if (!_Dictionary.ContainsKey(key)) {
                ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
                List<MemberBinding> memberBindingsList = 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);
                    memberBindingsList.Add(memberBinding);
                }
                foreach (var item in typeof(TOut).GetFields()) {
                    MemberExpression filed = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, filed);
                    memberBindingsList.Add(memberBinding);
                }
                MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingsList.ToArray());
                Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
                    {
                        parameterExpression
                    });
                Func<TIn, TOut> func = lambda.Compile();
                _Dictionary[key] = func;
            }
            return ((Func<TIn, TOut>)_Dictionary[key]).Invoke(tIn);
        }
    }

    class Student {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public void PrintAge() {
            Console.WriteLine(Age);
        }
    }

    class StudentDTO {
        public int ID { get; set; }
        public string Name { get; set; }
        //public string DickName { get; set; }
        public int Age { get; set; }
        public void PrintAge() {
            Console.WriteLine(Age);
        }
    }


    //表达式目录树+泛型缓存
    public class ExpressionGenericMapper<TIn, TOut> {
        private static Func<TIn, TOut> _FUNC = null;
        static ExpressionGenericMapper() {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
            List<MemberBinding> memberBindingsList = 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);
                memberBindingsList.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);
                memberBindingsList.Add(memberBinding);
            }
            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingsList.ToArray());
            Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
            {
                    parameterExpression
            });
            _FUNC = lambda.Compile();//拼装是一次性的
        }

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

}