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、循环用反射取对应属性,并且创建成员节点
2、循环里创建成员绑定节点,处理类中成员绑定关系
3、使用MemberInitExpression生成新对象节点,并将MemberBinding集合里的属性绑定到新对象中
4、自动生成的委托如下:
我们可以进行测试 :发现,调用该工具即可帮我们进行对象转换并且给属性赋值了
分类:
C#高级语法和底层原理
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?