C#表达式树浅析
一、前言
在我们日常开发中Lamba 表达式经常会使用,如List.Where(n=>Name="abc") 使用起来非常的方便,代码也很简洁,总之一个字就是“爽”。在之前我们总是用硬编码的方式去实现一些底层方法,比如我要查询用户“abc”是否存在,老的实现方式基本为:GetUser(string name) ,可能下次我需要按用户登录账号来查询,于是又得写一个方法:GetUserByLogin(string loginCode),我们认真想一下,如果能实现类似于集合查询那样只要写lambda 就能搞定,List.Where(n=>Name="abc"),List.Where(n=>LoginCode=="小A"),有了这样的想法,那我们也去了解一下lambda 表达式树的背后吧。
二、初识
表达式树关键字“Expressions”,我们在官方文档里面可以看到很多介绍,具体信息请查看微软官方文档库;官方文档里面的信息量比较大,有几十个对象的介绍:
这里我不建议大家从头到尾的看一遍,大致浏览就好了,因为信息量太多了。首先我们新建一个控制台程序,框架版本选FX4.0以上或者Core 都行,引入命名空间:
using System.Linq.Expressions; 接下来实现一个简单的功能,解析表达式: n=>n.Name="abc" 我们想要的结果是 Name="abc",有了这个目标我们就知道该干嘛了。
定义函数:private static string GetLambdaStr<T>(Expression<Func<T, bool>> expression),该函数定义了一个表达式树参数,Func<in T,out bool>是范型委托,该委托表示接收一个T类型参数,返回一个bool值。具体代码:
private static string GetLambdaStr<T>(Expression<Func<T, bool>> expression) { //解析表达式 //return new Analysis().AnalysisExpression(expression);
return null; }
接下来建立一个用户对象:
public class User { public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } public bool States { get; set; } }
再建立好测试代码:
//Expression<Func<T, bool>> lambda = n => n.Name == "abc"; Console.WriteLine("lambda : n => n.Name == \"abc\" "); var a = GetLambdaStr<User>(n => n.Name == "abc"); Console.WriteLine("result:" + a); Console.Write(Environment.NewLine); Console.ReadKey();
先不管那么多,我们调试进去看看表达式长啥样:
这样看比较清真,就是一个lambda表达式,我们展开看看对象明细:
看到这里我们是不是能想起点什么了,这其实就是一颗二叉树,显示的层次为根节点,左子节点,右子节点,依次循环。有了这个认知,我们立马能想到可以使用递归来遍历节点了。
于是我来了解表达式对象“Expression”有哪些属性和方法:
看到这里有点困惑了,刚刚我们明明看到有Left、Right 属性,但这里却没有,感觉好坑呀。没有左右节点我们根本不知道怎么去递归查找子节点呢。于是又去看官方介绍文档了,然后再仔细看了LambdaExpression 对象,这个是抽象类,有抽象必定有相关的实现或者提供对外属性,仔细一找,刚好找到BinaryExpression对象,有Left、Right属性同时继承了Expression对象,也提供了LambdaExpression 属性,这个就是我们要找的对象了,可以说是峰回路转了:
顺着这个思路,我又找到了属性成员和属性值对象MemberExpression、ConstantExpression,我们来实现关键代码