• .net core 高性能对象映射


    关于对象转换已经有不少轮子(AutoMapper,TinyMapper) .出于项目需要,手动造一个简单轮子。先贴代码

    1.采用静态泛型类缓存,避免了拆箱装箱操作。

    2.对于转换对象中有,字段名一样但是类型不一样的类时仍可以用

      

     1     public static class Mapper<TSource, TTarget> where TSource : class where TTarget : class
     2     {
     3         public readonly static Func<TSource, TTarget> Map;
     4 
     5         static Mapper()
     6         {
     7             if (Map == null)
     8                 Map = GetMap();
     9         }
    10 
    11         private static Func<TSource, TTarget> GetMap()
    12         {
    13             var sourceType = typeof(TSource);
    14             var targetType = typeof(TTarget);
    15 
    16             var parameterExpression = Expression.Parameter(sourceType, "p");
    17             var memberInitExpression = GetExpression(parameterExpression, sourceType, targetType);
    18 
    19             var lambda = Expression.Lambda<Func<TSource, TTarget>>(memberInitExpression, parameterExpression);
    20             return lambda.Compile();
    21         }
    22 
    23         /// <summary>
    24         /// 根据转换源和目标获取表达式树
    25         /// </summary>
    26         /// <param name="parameterExpression">表达式参数p</param>
    27         /// <param name="sourceType">转换源类型</param>
    28         /// <param name="targetType">转换目标类型</param>
    29         /// <returns></returns>
    30         private static MemberInitExpression GetExpression(Expression parameterExpression, Type sourceType, Type targetType)
    31         {
    32             var memberBindings = new List<MemberBinding>();
    33             foreach (var targetItem in targetType.GetProperties().Where(x => x.PropertyType.IsPublic && x.CanWrite))
    34             {
    35                 var sourceItem = sourceType.GetProperty(targetItem.Name);
    36 
    37                 //判断实体的读写权限
    38                 if (sourceItem == null || !sourceItem.CanRead || sourceItem.PropertyType.IsNotPublic)
    39                     continue;
    40 
    41                 //标注NotMapped特性的属性忽略转换
    42                 if (sourceItem.GetCustomAttribute<NotMappedAttribute>() != null)
    43                     continue;
    44 
    45                 var propertyExpression = Expression.Property(parameterExpression, sourceItem);
    46 
    47                 //判断都是class 且类型不相同时
    48                 if (targetItem.PropertyType.IsClass && sourceItem.PropertyType.IsClass && targetItem.PropertyType != sourceItem.PropertyType)
    49                 {
    50                     if (targetItem.PropertyType != targetType)//防止出现自己引用自己无限递归
    51                     {
    52                         var memberInit = GetExpression(propertyExpression, sourceItem.PropertyType, targetItem.PropertyType);
    53                         memberBindings.Add(Expression.Bind(targetItem, memberInit));
    54                         continue;
    55                     }
    56                 }
    57 
    58                 if (targetItem.PropertyType != sourceItem.PropertyType)
    59                     continue;
    60 
    61                 memberBindings.Add(Expression.Bind(targetItem, propertyExpression));
    62             }
    63             return Expression.MemberInit(Expression.New(targetType), memberBindings);
    64         }
    65     }
    View Code

    3.调用方法如下

     (1)构造样例类

        public class A
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public C User { get; set; }
    
            /// <summary>
            /// 标注为notmapped特性时,不转换赋值
            /// </summary>
            [System.ComponentModel.DataAnnotations.Schema.NotMapped]
            public D UserA { get; set; }
    
        }
    
        public class B
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public D User { get; set; }
    public D UserA { get; set; } } public class C { public int Id { get; set; } public string Name { get; set; } } public class D { public int Id { get; set; } public string Name { get; set; } }

      

      (2) 调用

                var a = new A
                {
                    Id = 1,
                    Name = "张三",
                    User = new C
                    {
                        Id = 1,
                        Name = "李四"
                    }
                };
    B b = Mapper<A, B>.Map(a);//得到转换结果

      

    4.性能测试

     1             var length = 10000000;
     2             var listA = new List<A>();
     3             for (int i = 0; i < length; i++)
     4             {
     5                 listA.Add(new A
     6                 {
     7                     Id = i,
     8                     Name = "张三",
     9                     User = new C
    10                     {
    11                         Id = i,
    12                         Name = "李四"
    13                     }
    14                 });
    15             }
    16 
    17             var sw = Stopwatch.StartNew();
    18             for (int i = 0; i < length; i++)
    19             {
    20                 var item = listA[i];
    21                 var b = new B
    22                 {
    23                     Id = item.Id,
    24                     Name = item.Name,
    25                     User = new D
    26                     {
    27                         Id = i,
    28                         Name = "李四",
    29                     }
    30                 };
    31             }
    32             sw.Stop();
    33             Console.WriteLine($"原生的时间:{sw.ElapsedMilliseconds}ms");
    34 
    35             //表达式
    36             Mapper<A, B>.Map(listA[0]);//预先编译缓存
    37             sw.Restart();
    38             for (int i = 0; i < length; i++)
    39             {
    40                 Mapper<A, B>.Map(listA[i]);
    41             }
    42             sw.Stop();
    43             Console.WriteLine($"表达式的时间:{sw.ElapsedMilliseconds}ms");
    44 
    45             //AutoMapper
    46             AutoMapper.Mapper.Initialize(cfg => cfg.CreateMap<A, B>());
    47             sw.Restart();
    48             for (int i = 0; i < length; i++)
    49             {
    50                 var b = AutoMapper.Mapper.Map<B>(listA[i]);
    51             }
    52             sw.Stop();
    53             Console.WriteLine($"AutoMapper时间:{sw.ElapsedMilliseconds}ms");
    54 
    55             //TinyMapper
    56             TinyMapper.Bind<A, B>();
    57             sw.Restart();
    58             for (int i = 0; i < length; i++)
    59             {
    60                 var b = TinyMapper.Map<B>(listA[i]);
    61             }
    62             sw.Stop();
    63             Console.WriteLine($"TinyMapper时间:{sw.ElapsedMilliseconds}ms");
    64 
    65             Console.ReadLine();
    View Code

    5. 1000万数据不带子类集结果

    6. 1000万数据带子类集结果 

  • 相关阅读:
    SSH学习-struts2整合spring报错'Could not open ServletContext resource [/WEB-INF/applicationContext.xml]'
    YAML学习
    配置composer代理
    Windows下配置PHPUnit(pear已弃用,使用phpunit.phar)
    算法-第四版-练习1.3.9解答
    算法-第四版-练习1.3.10解答
    算法-第四版-练习1.3.11解答
    算法-第四版-练习1.3.12解答
    算法-第四版-练习1.3.13解答
    算法-第四版-练习1.3.14解答
  • 原文地址:https://www.cnblogs.com/castyuan/p/9285101.html
Copyright © 2020-2023  润新知