12ExpressionTree应用场景一

1、AutoMapper自动映射框架:用于不同类之间的相互转换,原理就是通过表达式树来实现的。

不同类相互转换有多种方式,比如反射,拿到一个类里的所有属性再循环复制给另一个类。或者是通过序列化和反序列化将连个 类互相转换,不过效率都没有通过表达式树效率高。

我们有时候需要进行对象转换:

我们定义如下两个类:

public class Student
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Age { get; set; }
        }


        public class Person
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Age { get; set; }
        }

那么我们如果有逻辑需要将学生类转为person类的话,最直接的方法就是声明好将学生类中对应的成员的值赋值给person类

Student student = new Student()
            {
                Id = 1,
                Name = "张三",
                Age = 18
            };


            Person newStudent = new Person()
            {
                Id = student.Id,
                Name = student.Name,
                Age = student.Age
            };

可以看出字段少的话没啥问题,字段多就会很繁琐。

创建自动对象转换器

首先我们创建一个ExpressionMapper泛型类,需要两个泛型类型,TIn, TOut,TIn代表要被转换的类, TOut代表转换为该类

public class ExpressionMapper<TIn, TOut>
    {
        //表达式树自动创建对象转换器委托
        private static Func<TIn, TOut> func = null;

        //通过类名.MyMapper方法时候会自动执行该构造函数
        static ExpressionMapper()
        {

            //创建参数表达式
            ParameterExpression parameterExp = Expression.Parameter(typeof(TIn), "p");

            //创建一个类的成员绑定的集合
            List<MemberBinding> memberBindingList = new List<MemberBinding>();

            //通过反射获取TOut类的所有属性并且遍历
            foreach (var item in typeof(TOut).GetProperties())
            {

                //得到成员表达式,相当于新属性
                MemberExpression member = Expression.Property(parameterExp, typeof(TIn).GetProperty(item.Name));

                //进行属性绑定,相当于属性初始化,给新属性赋值,表示新属性的值对应的旧属性的值
                MemberBinding memberBinding = Expression.Bind(item, member);//item:要转为的类的属性,member:被转换的类的属性
                //添加到类成员属性绑定集合
                memberBindingList.Add(memberBinding);

            }


            //通过反射获取TOut类的所有自动并且遍历
            foreach (var item in typeof(TOut).GetFields())
            {

                //得到成员表达式,相当于新属性
                MemberExpression member = Expression.Field(parameterExp, typeof(TIn).GetField(item.Name));

                //进行属性绑定,相当于属性初始化,给新属性赋值
                MemberBinding memberBinding = Expression.Bind(item, member);

                memberBindingList.Add(memberBinding);

            }

            //创建新对象并初始化,生成成员表达式
            MemberInitExpression memberInitExpression =Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());

            //生成表达式
            Expression<Func<TIn, TOut>> expression = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] { parameterExp });


            //编译,然后将表达式赋值给一个委托
            func = expression.Compile();

        }

        //调用该委托的方法
        public static TOut MyMapper(TIn t)
        {
            //调用这个类的委托即可
            return func(t);
        }

    }

该类中几个Expression节点的图解
1、循环用反射取对应属性,并且创建成员节点
image

2、循环里创建成员绑定节点,处理类中成员绑定关系
image

3、使用MemberInitExpression生成新对象节点,并将MemberBinding集合里的属性绑定到新对象中
image

4、自动生成的委托如下:
image

我们可以进行测试 :发现,调用该工具即可帮我们进行对象转换并且给属性赋值了
image

posted @   青仙  阅读(71)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示