zoukankan      html  css  js  c++  java
  • .net5

    方式一:自定义1

    方法类:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    
    namespace NetFive.UnitTest
    {
        /// <summary>
        /// 关于对象转换已经有不少轮子(AutoMapper,TinyMapper) .出于项目需要,手动造一个简单轮子。先贴代码
        /// 1.采用静态泛型类缓存,避免了拆箱装箱操作。
        /// 2.对于转换对象中有,字段名一样但是类型不一样的类时仍可以用
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TTarget"></typeparam>
        public static class Mapper<TSource, TTarget> where TSource : class where TTarget : class
        {
            public readonly static Func<TSource, TTarget> Map;
    
            static Mapper()
            {
                if (Map == null)
                    Map = GetMap();
            }
    
            private static Func<TSource, TTarget> GetMap()
            {
                var sourceType = typeof(TSource);
                var targetType = typeof(TTarget);
    
                var parameterExpression = Expression.Parameter(sourceType, "p");
                var memberInitExpression = GetExpression(parameterExpression, sourceType, targetType);
    
                var lambda = Expression.Lambda<Func<TSource, TTarget>>(memberInitExpression, parameterExpression);
                return lambda.Compile();
            }
    
            /// <summary>
            /// 根据转换源和目标获取表达式树
            /// </summary>
            /// <param name="parameterExpression">表达式参数p</param>
            /// <param name="sourceType">转换源类型</param>
            /// <param name="targetType">转换目标类型</param>
            /// <returns></returns>
            private static MemberInitExpression GetExpression(Expression parameterExpression, Type sourceType, Type targetType)
            {
                var memberBindings = new List<MemberBinding>();
                foreach (var targetItem in targetType.GetProperties().Where(x => x.PropertyType.IsPublic && x.CanWrite))
                {
                    var sourceItem = sourceType.GetProperty(targetItem.Name);
    
                    //判断实体的读写权限
                    if (sourceItem == null || !sourceItem.CanRead || sourceItem.PropertyType.IsNotPublic)
                        continue;
    
                    //标注NotMapped特性的属性忽略转换
                    if (sourceItem.GetCustomAttribute<NotMappedAttribute>() != null)
                        continue;
    
                    var propertyExpression = Expression.Property(parameterExpression, sourceItem);
    
                    //判断都是class 且类型不相同时
                    if (targetItem.PropertyType.IsClass && sourceItem.PropertyType.IsClass && targetItem.PropertyType != sourceItem.PropertyType)
                    {
                        if (targetItem.PropertyType != targetType)//防止出现自己引用自己无限递归
                        {
                            var memberInit = GetExpression(propertyExpression, sourceItem.PropertyType, targetItem.PropertyType);
                            memberBindings.Add(Expression.Bind(targetItem, memberInit));
                            continue;
                        }
                    }
    
                    if (targetItem.PropertyType != sourceItem.PropertyType)
                        continue;
    
                    memberBindings.Add(Expression.Bind(targetItem, propertyExpression));
                }
                return Expression.MemberInit(Expression.New(targetType), memberBindings);
            }
        }
    }
    

     测试类:

    using System;
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace NetFive.UnitTest
    {
        public class AddEmployeeDto
        {
            public AddEmployeeDto()
            {
                EmpId = 1;
                EmpNo = "1001";
                EmpName = "网易";
                Gender = Genders.男;
                EntryDate = DateTime.Now;
                QuitDate = null;
                Outsource = true;
            }
    
            /// <summary>
            /// 编号
            /// </summary>
            public int EmpId { get; set; }
    
            /// <summary>
            /// 工号
            /// </summary>
            public string EmpNo { get; set; }
    
            /// <summary>
            /// 姓名
            /// </summary>
            [NotMapped]//标注为 NotMapped 特性时,不转换赋值
            public string EmpName { get; set; }
    
            /// <summary>
            /// 性别
            /// </summary>
            public Genders Gender { get; set; }
    
            /// <summary>
            /// 入职时间
            /// </summary>
            public DateTime EntryDate { get; set; }
    
            /// <summary>
            /// 离职时间
            /// </summary>
            public DateTime? QuitDate { get; set; }
    
            /// <summary>
            /// 是否外包
            /// </summary>
            public bool Outsource { get; set; }
    
            public override string ToString()
            {
                return EmpId + "-" + EmpNo + "-" + EmpName + "-" + Gender.ToString() + EntryDate.ToString() + "-" + (QuitDate.HasValue ? QuitDate.ToString() : "") + "-" + Outsource;
            }
    
        }
    }
    
    using System;
    using System.Collections.Generic;
    
    namespace NetFive.UnitTest
    {
        public class EmployeeInfo
        {
            /// <summary>
            /// 编号
            /// </summary>
            public int EmpId { get; set; }
    
            /// <summary>
            /// 工号
            /// </summary>
            public string EmpNo { get; set; }
    
            /// <summary>
            /// 姓名
            /// </summary>
            /// </summary>
            public string EmpName { get; set; }
    
            /// <summary>
            /// 性别
            /// </summary>
            public Genders Gender { get; set; }
    
            /// <summary>
            /// 入职时间
            /// </summary>
            public DateTime EntryDate { get; set; }
    
            /// <summary>
            /// 离职时间
            /// </summary>
            public DateTime? QuitDate { get; set; }
    
            /// <summary>
            /// 是否外包
            /// </summary>
            public bool Outsource { get; set; }
    
            public static IList<EmployeeInfo> ListEmployee(int length)
            {
                IList<EmployeeInfo> employeeInfos = new List<EmployeeInfo>();
                EmployeeInfo entity = new EmployeeInfo();
                for (int i = 1; i <= length; i++)
                {
                    entity.EmpId = i;
                    entity.EmpNo = "No" + i;
                    entity.EmpName = "Name" + i;
                    entity.Gender = i % 2 == 0 ? Genders.女 : Genders.男;
                    entity.EntryDate = DateTime.Now.AddDays(-i);
                    entity.Outsource = i % 2 == 0;
                    employeeInfos.Add(entity);
                }
                return employeeInfos;
            }
    
            public override string ToString()
            {
                return EmpId + "-" + EmpNo + "-" + EmpName + "-" + Gender.ToString() + EntryDate.ToString() + "-" + (QuitDate.HasValue ? QuitDate.ToString() : "") + "-" + Outsource;
            }
        }
    
        /// <summary>
        /// 性别
        /// </summary>
        public enum Genders
        {
            女 = 0,
            男 = 1
        }
    }
    

     测试:

                //单对象
                //多对象需要循环,但查询多对象时建议使用强类型【直接输出Dto】
                //参数为null时会报错,在使用方法前需要判断是否为null
                AddEmployeeDto add = new AddEmployeeDto();
                EmployeeInfo entity = Mapper<AddEmployeeDto, EmployeeInfo>.Map(add);
                Console.WriteLine(add.ToString());
                Console.WriteLine(entity.ToString());
    

      

     方式2:自定义2

     自定义类:

    using System;
    using System.Collections.Generic;
    
    namespace XXX.Common
    {
        /// <summary>
        /// 常用工具
        /// </summary>
        public class XXXUtil
        {
            #region 克隆对象
            /// <summary>
            /// 克隆对象
            /// </summary>
            /// <param name="target">目标</param>
            /// <param name="source">数据源</param>
            public static void CopyModel(object target, object source)
            {
                Type type1 = target.GetType();
                Type type2 = source.GetType();
                foreach (var mi in type2.GetProperties())
                {
                    var des = type1.GetProperty(mi.Name);
                    if (des != null)
                    {
                        des.SetValue(target, mi.GetValue(source, null), null);
                    }
                }
            }
            #endregion
    
            #region 克隆对象列表
            public static List<T> Clone<T, TEntity>(IList<TEntity> list) where T : new()
            {
                if (list.Count == 0)
                {
                    return new List<T>();
                }
                List<T> items = new List<T>();
                foreach (var m in list)
                {
                    var model = new T();
                    var ps = model.GetType().GetProperties();
                    var properties = m.GetType().GetProperties();
                    foreach (var p in properties)
                    {
                        foreach (var pm in ps)
                        {
                            if (pm.Name == p.Name)
                            {
                                pm.SetValue(model, p.GetValue(m));
                            }
                        }
                    }
                    items.Add(model);
                }
                return items;
            }
            #endregion
    }
    

     调用方式:

    单对象:
    EmployeeInfo addEmployeeInfo = new EmployeeInfo();
    SupernodeUtil.CopyModel(addEmployeeInfo, entity);
    多对象:
    var datas = SupernodeUtil.Clone<EmployeeShowDto, EmployeeInfo>(employeeInfos);
    

      

     方式3:AutoMapper

     NuGet包:[XXX.Service]

    AutoMapper
    AutoMapper.Extensions.Microsoft.DependencyInjection
    

     注意:左为要转换的数据类型,右边是转换后的数据类型。

    WebApi项目下新建文件夹:【Custom/Mapper】 

    using AutoMapper;
    using NetFive.Model.Entity;
    using NetFive.Service.Employee.Dto;
    
    namespace NetFive.WebApi.Custom.Mapper
    {
        public class AutoMapperConfigs : Profile
        {
            /// <summary>
            /// 配置互相转换的类
            /// </summary>
            public AutoMapperConfigs()
            {
                CreateMap<AddEmployeeDto, EmployeeInfo>();
                CreateMap<EmployeeInfo, EmployeeShowDto>();
            }
        }
    }
    

     Startup注册:

                #region AutoMapper
                //添加对AutoMapper的支持
                services.AddAutoMapper(typeof(AutoMapperConfigs));
                #endregion
    

     调用方式:

    private readonly IMapper _mapper;
    public EmployeeService(IMapper mapper) 
    {
        _mapper = mapper;
    }
    单对象:
    EmployeeInfo entity = _mapper.Map<AddEmployeeDto, EmployeeInfo>(add);
    多对象:
    IList<EmployeeInfo> employeeInfos = EmployeeInfo.ListEmployee(100);
    IList<EmployeeShowDto> showDtos = _mapper.Map<IList<EmployeeShowDto>>(employeeInfos);
    

     当参数为null时:

     方式4:TinyMapper【实体类用上面的】

     NuGet包:

    TinyMapper
    

     调用方式:

                AddEmployeeDto add = new AddEmployeeDto();
                TinyMapper.Bind<AddEmployeeDto, EmployeeInfo>();
                var info = TinyMapper.Map<EmployeeInfo>(add);
                Console.WriteLine(info.ToString());
    

     忽略某些字段或者绑定不同字段:

                //对象名称不一样,而且需要忽略某些字段
                //比如修改EmployeeInfo 的EmpName字段为Name字段
                AddEmployeeDto add = new AddEmployeeDto();
                TinyMapper.Bind<AddEmployeeDto, EmployeeInfo>(config =>
                {
                    config.Ignore(x => x.EmpId);//忽略 EmpId 字段
                    config.Bind(x => x.EmpName, y => y.Name);//将源类型和目标类型的字段对应绑定起来
                });
                var info = TinyMapper.Map<EmployeeInfo>(add);
                Console.WriteLine(info.ToString());
    

     复杂类型使用:类中类,类中List数组类,使用方式和上面一样,测试无问题

     

    为null时,会报异常:Value cannot be null. 所以使用TinyMapper需要判断是否为null

     效率:来源于其他人的测试

     自定义1 > AutoMapper > TinyMapper

  • 相关阅读:
    对于WP你所要了解的一些数字
    Win8系统太难用,再也不用了
    WP8下一些图片图标的常识(菜鸟篇)
    Wp8程序加载运行顺序(菜鸟篇)
    DLNA介绍(包括UPnP)
    一个通用的WPF值转换器
    C#创建Windows服务
    Spring.Net+NHibenate+Asp.Net mvc +ExtJs 系列 3 数据访问层
    Spring.Net+NHibenate+Asp.Net mvc +ExtJs 系列 1准备
    ASP.NET MVC Localization Helpers (本地化帮助方法)
  • 原文地址:https://www.cnblogs.com/gygtech/p/14490794.html
Copyright © 2011-2022 走看看