今天我们来聊一下表达式目录树,什么是表达式目录树?为什么会出现表达式目录树?表达式目录树跟委托又有什么区别?
委托:委托类似于一种安全的指针引用,在使用它时是当作一个类型而不是一个方法,相当于对一组方法的列表引用。事件是委托的一个实例。
表达式目录树:表达式目录树是一种数据结构体,用于存储运算的一种结构,也可以叫做语法树,用于表示Lambda表达式逻辑的一种数据结构,(注意方法体只能有一行)。
首先我们来看一下委托和表达式目录树长什么样子?
//有返回值的委托
Func<int, int, int> func = (m, n) => m * n + 2;
//表达式目录树
Expression<Func<int, int, int>> exp = (m, n) => m * n + 2;
从上面看我们感觉表达式目录树和委托长的‘好像’,简直一模一样,这能有什么区别呢?然后带着大家看一下反编译出来代码大家就明白了。
其实从反编译工具中我们已经很清楚的看出来委托和表达式目录树完全是两码事,委托最终是调用的一个方法 ,表达式目录树则更像一种数据结构,从反编译的代码中可以看出在一步一步的按左边右边解析表达式。
其实从上面的概念和反编译的结果来看大家应该差不多知道什么叫表达式目录树了。
那为什么会出现表达式目录树呢?首先我们要去了解表达式目录的内在才知道它到底有什么作用。
其实上面我们已经看到了反编译出来的代码。那么我们可以在代码自己去拼接表达式目录树嘛?答案当然是肯定可以了。
我们根据反编译出来的代码就很容易去拼装一个表达式目录树
public static void Show()
{
//参数(m,n)
ParameterExpression parameterExpression1 = Expression.Parameter(typeof(int), "m");
ParameterExpression parameterExpression2 = Expression.Parameter(typeof(int), "n");
//常量 (2)
ConstantExpression constant = Expression.Constant(2, typeof(int));
//乘法 (m*n)
BinaryExpression binary = Expression.Multiply(parameterExpression1, parameterExpression2);
//相加 ((m*n)+2)
BinaryExpression binaryAdd = Expression.Add(binary, constant);
Expression<Func<int, int, int>> expression = Expression.Lambda<Func<int, int, int>>(binaryAdd, new ParameterExpression[]
{
parameterExpression1,
parameterExpression2
});
//编译出一个委托
Func<int, int, int> func = expression.Compile();
//调用委托
int iResult3 = func.Invoke(4, 5);
}
其实到这里大家应该就可以想象出我们可以自己封装做出一些不一样的东西,比如我们在项目有很多需要这个类属性值赋值给另一个类属性值的一些操作,展开想象使用表达式目录树就可封装出一个一劳永逸的方法。
public static void Show1()
{
User user = new User()
{
Id = 1,
Name = "测试"
};
ParameterExpression parameterExpression = Expression.Parameter(typeof(User), "u");
List<MemberBinding> memberBindingList = new List<MemberBinding>();
foreach (var item in typeof(UserDto).GetProperties())
{
MemberExpression property = Expression.Property(parameterExpression, typeof(User).GetProperty(item.Name));
MemberBinding memberBinding = Expression.Bind(item, property);
memberBindingList.Add(memberBinding);
}
foreach (var item in typeof(UserDto).GetFields())
{
MemberExpression property = Expression.Field(parameterExpression, typeof(User).GetField(item.Name));
MemberBinding memberBinding = Expression.Bind(item, property);
memberBindingList.Add(memberBinding);
}
MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(UserDto)), memberBindingList);
Expression<Func<User, UserDto>> lambda2 = Expression.Lambda<Func<User, UserDto>>(memberInitExpression, new ParameterExpression[]
{
parameterExpression
});
Func<User, UserDto> func = lambda2.Compile();
UserDto copy = func(user);
}
漂亮,但这还不是最优美的,其实到这里大家可能会有个疑问这样会不会效率比较低,那比起直接赋值效率肯定会低,但我们使用泛型+缓存效率肯定会事半功倍,这样我们就可以既做到效率没有那么低,又能做到一劳永逸,完美!至于泛型+缓存我这里就不展示了,下一次我们更进一步的了解学习表达式目录树。希望大佬们多多指导纠正小萌新,大家一起学习进步!!!