.NET Core 高性能对象转换

2018 年 7 月 20 日 DotNet

(点击上方蓝字,可快速关注我们)


来源:COSTYUAN

cnblogs.com/castyuan/p/9285101.html


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


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


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


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);

    }

}


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; }<br>

    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 = "李四"

    }

};<br>

B b = Mapper<A, B>.Map(a);//得到转换结果


4、性能测试


var length = 10000000;

var listA = new List<A>();

for (int i = 0; i < length; i++)

{

    listA.Add(new A

    {

        Id = i,

        Name = "张三",

        User = new C

        {

            Id = i,

            Name = "李四"

        }

    });

}


var sw = Stopwatch.StartNew();

for (int i = 0; i < length; i++)

{

    var item = listA[i];

    var b = new B

    {

        Id = item.Id,

        Name = item.Name,

        User = new D

        {

            Id = i,

            Name = "李四",

        }

    };

}

sw.Stop();

Console.WriteLine($"原生的时间:{sw.ElapsedMilliseconds}ms");


//表达式

Mapper<A, B>.Map(listA[0]);//预先编译缓存

sw.Restart();

for (int i = 0; i < length; i++)

{

    Mapper<A, B>.Map(listA[i]);

}

sw.Stop();

Console.WriteLine($"表达式的时间:{sw.ElapsedMilliseconds}ms");


//AutoMapper

AutoMapper.Mapper.Initialize(cfg => cfg.CreateMap<A, B>());

sw.Restart();

for (int i = 0; i < length; i++)

{

    var b = AutoMapper.Mapper.Map<B>(listA[i]);

}

sw.Stop();

Console.WriteLine($"AutoMapper时间:{sw.ElapsedMilliseconds}ms");


//TinyMapper

TinyMapper.Bind<A, B>();

sw.Restart();

for (int i = 0; i < length; i++)

{

    var b = TinyMapper.Map<B>(listA[i]);

}

sw.Stop();

Console.WriteLine($"TinyMapper时间:{sw.ElapsedMilliseconds}ms");

Console.ReadLine();


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



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



看完本文有收获?请转发分享给更多人

关注「DotNet」,提升.Net技能 

登录查看更多
0

相关内容

.NET 框架(.NET Framework) 是由微软开发,一个致力于敏捷软件开发、快速应用开发、平台无关性和网络透明化的软件开发平台。
COVID-19文献知识图谱构建,UIUC-哥伦比亚大学
专知会员服务
42+阅读 · 2020年7月2日
【2020新书】实战R语言4,323页pdf
专知会员服务
100+阅读 · 2020年7月1日
Python导论,476页pdf,现代Python计算
专知会员服务
259+阅读 · 2020年5月17日
专知会员服务
155+阅读 · 2020年4月21日
【SIGMOD2020-腾讯】Web规模本体可扩展构建
专知会员服务
29+阅读 · 2020年4月12日
临床自然语言处理中的嵌入综述,SECNLP: A survey of embeddings
机器学习计算距离和相似度的方法
极市平台
10+阅读 · 2019年9月20日
人脸检测库:libfacedetection
Python程序员
15+阅读 · 2019年3月22日
Github 项目推荐 | 用 PyTorch 0.4 实现的 YoloV3
AI研习社
9+阅读 · 2018年8月11日
.NET Core 环境下构建强大且易用的规则引擎
Tensor Flow、Caffe、Torch共同之处:敞开的漏洞!
干货 | PyTorch相比TensorFlow,存在哪些自身优势?
全球人工智能
10+阅读 · 2017年9月30日
python pandas 数据处理
Python技术博文
4+阅读 · 2017年8月30日
VIP会员
相关资讯
机器学习计算距离和相似度的方法
极市平台
10+阅读 · 2019年9月20日
人脸检测库:libfacedetection
Python程序员
15+阅读 · 2019年3月22日
Github 项目推荐 | 用 PyTorch 0.4 实现的 YoloV3
AI研习社
9+阅读 · 2018年8月11日
.NET Core 环境下构建强大且易用的规则引擎
Tensor Flow、Caffe、Torch共同之处:敞开的漏洞!
干货 | PyTorch相比TensorFlow,存在哪些自身优势?
全球人工智能
10+阅读 · 2017年9月30日
python pandas 数据处理
Python技术博文
4+阅读 · 2017年8月30日
Top
微信扫码咨询专知VIP会员