AutoMapper MapHelper

本文提供两种mapper方式

  1. 反射
  2. 表达式(性能比反射更高)

测试运行一百万次映射,硬编码大概在15毫秒,反射560毫秒,表达式150毫秒


    public static class MapperHelper
    {
        /// <summary>
        /// 将数据映射到指定的对象中
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="obj"></param>
        /// <param name="outObj"></param>
        /// <param name="ignorDesc"></param>
        /// <returns></returns>
        public static TOut AutoMap<TIn, TOut>(TIn obj, TOut outObj, bool ignorDesc = true) where TOut : new()
        {
            return AutoMap(obj, ignorDesc, outObj);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="obj"></param>
        /// <param name="ignorDesc">忽略description描述信息</param>
        /// <returns></returns>
        public static TOut AutoMap<TIn, TOut>(TIn obj, bool ignorDesc = true) where TOut : new()
        {
            TOut result = new TOut();
            return AutoMap(obj, ignorDesc, result);
        }

        private static TOut AutoMap<TIn, TOut>(TIn obj, bool ignorDesc, TOut result) where TOut : new()
        {
            System.Reflection.PropertyInfo[] properties = obj.GetType().GetProperties();

            //存储源对象属性
            Dictionary<string, PropertyInfo> propertiesDic = new Dictionary<string, PropertyInfo>();
            foreach (System.Reflection.PropertyInfo item in properties)
            {
                var hasSameKey = properties.Count(f => f.Name == item.Name) > 1;
                var isHideBySig = item.GetGetMethod().IsHideBySig;

                //避免因为子类添加new修饰符符导致出现重名字段
                if (hasSameKey && isHideBySig && item.DeclaringType != obj.GetType())
                {
                    continue;
                }
                propertiesDic.Add(item.Name, item);
            }

            System.Reflection.PropertyInfo[] resultProperties = result.GetType().GetProperties();

            foreach (System.Reflection.PropertyInfo j in resultProperties)
            {
                try
                {
                    ////自定义属性处理别名
                    DescriptionAttribute desc = (DescriptionAttribute)j.GetCustomAttributes(false).FirstOrDefault(f => f.GetType() == typeof(DescriptionAttribute));
                    if (desc != null && !ignorDesc)
                    {
                        string desName = desc.Description;
                        if (propertiesDic.ContainsKey(desName))
                        {
                            j.SetValue(result, propertiesDic[desName].GetValue(obj));
                            continue;
                        }
                    }
                    else
                    {
                        if (propertiesDic.ContainsKey(j.Name))
                        {
                            j.SetValue(result, propertiesDic[j.Name].GetValue(obj));
                        }
                    }
                }
                catch (Exception)
                {
                    try
                    {
                        j.SetValue(result, Activator.CreateInstance(j.PropertyType));
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("转换前后类型不一致");
                    }
                }
            }
            return result;
        }

        public static IList<TOut> AutoMap<TIn, TOut>(this List<TIn> list, bool ignorDesc = true) where TOut : new()
        {
            List<TOut> result = new List<TOut>();
            foreach (TIn item in list)
            {
                try
                {
                    result.Add(AutoMap<TIn, TOut>(item, ignorDesc));
                }
                catch (Exception e)
                {
                    throw e;
                }
            }
            return result;
        }


        public static object AutoMapByType(object obj, Type outType, bool ignorDesc = false)
        {
            object result = Activator.CreateInstance(outType);

            System.Reflection.PropertyInfo[] properties = obj.GetType().GetProperties();

            //存储源对象属性
            Dictionary<string, PropertyInfo> propertiesDic = new Dictionary<string, PropertyInfo>();
            foreach (System.Reflection.PropertyInfo item in properties)
            {
                propertiesDic.Add(item.Name, item);
            }

            System.Reflection.PropertyInfo[] resultProperties = outType.GetProperties();

            foreach (System.Reflection.PropertyInfo j in resultProperties)
            {
                try
                {
                    ////自定义属性处理别名
                    DescriptionAttribute desc = (DescriptionAttribute)j.GetCustomAttributes(false).FirstOrDefault(f => f.GetType() == typeof(DescriptionAttribute));
                    if (desc != null && !ignorDesc)
                    {
                        string desName = desc.Description;
                        if (propertiesDic.ContainsKey(desName))
                        {
                            j.SetValue(result, propertiesDic[desName].GetValue(obj));
                            continue;
                        }
                    }
                    else
                    {
                        if (propertiesDic.ContainsKey(j.Name))
                        {
                            j.SetValue(result, propertiesDic[j.Name].GetValue(obj));
                        }
                    }
                }
                catch (Exception)
                {
                    try
                    {
                        j.SetValue(result, Activator.CreateInstance(j.PropertyType));
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("转换前后类型不一致");
                    }
                }
            }
            return result;
        }
    }

上面使用的是反射的模式,性能虽然比反序列化要高,可还是比硬编码低很多,可以采用表达式的方法来提高性能(性能接近硬编码-约比反射模式性能高30倍)


    public static class ExpressionMapper
    {
        /// <summary>
        /// 字典缓存,保存的是委托,委托内部是转换的动作
        /// </summary>
        private static Dictionary<string, object> _Dic = new Dictionary<string, object>();

        /// <summary>
        /// Expression动态拼接+普通缓存
        /// </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 (!_Dic.ContainsKey(key))
            {
                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<TIn, TOut> func = lambda.Compile();//拼装是一次性的
                _Dic[key] = func;
            }
            return ((Func<TIn, TOut>)_Dic[key]).Invoke(tIn);
        }
    }

调用方法

var resultA = ExpressionMapper.Trans<MapperModelB, MapperModelA>(datab);

[参考]
C# Expression详解

posted @ 2022-12-01 09:48  Hey,Coder!  阅读(29)  评论(0编辑  收藏  举报