随着Linq的盛行,对于Linq和Lmabda表达式的使用也越来越多,Lambda表达式在.net framework 3.5中提出来,Lambda表达式是一个匿名方法,通常在LINQ中被用来创建委托,但是当我们利用Lmabda表达式来实现某些操作的时候,分解内部的表达式树结构就很重要了,例如我们要在一些方法调用当中直接使用 t => t.Name 的方式将属性Name获取出来,这样我们就不用自己去写字符串,且在属性发生改变的时候编译器可以帮助我们进行重构和检测。
当我们要实现以上方式的时候,就不再只是匿名委托了,而是要使用到Expression,它位于System.Linq.Expressions命名空间内,具体的资料大家可以到MSDN内找到,这里就不具体列出来了。在表达式内{ 类.属性 }的格式是一个MemberExpression对象,节点类型是MemberAccess,由于我们要获取的属性对应的类型不一定都一样,因此获取属性名的委托就只能定义为Func<T, object>了,大致代码如下:
public static string ResloveName<T>(Expression<Func<T, object>> expression) { var exp = expression.Body as MemberExpression; string expStr = exp.ToString(); return expStr.Substring(expStr.IndexOf(".") + 1); }
现在有如下代码:
User user = new User { Name = "Xiao Ming" }; Expression<Func<User, bool>> exp = u => u.Name == user.Name;
假如要利用这个二元表达式来构建SQL的话,应该如何去分解这个表达式呢,我的做法是首先将表达式的主体转化为BinaryExpression,然后分别去判断Left、Right属性内的表达式(Left、Right属性表达式都是MemberExpression)的Expression是否跟exp的参数表达式相同,将不同的表达式的值计算出来,用于当作参数,大致代码如下:
BinaryExpression binaryExp = exp.Body as BinaryExpression; Expression constantExp = (binaryExp.Left as MemberExpression).Expression == exp.Parameters[0] ? binaryExp.Right : binaryExp.Left; string value = Expression.Lambda(constantExp).Compile().DynamicInvoke().ToString();
从继承体系上看,可以发现所有泛型表达式都是继承自LambdaExpression的,因此可以重载一个方法,大致代码如下:
public static string ResloveName(Expression<Func<T, object>> expression) { return ResloveName(expression as LambdaExpression); } public static string ResloveName(LambdaExpression expression) { var exp = expression.Body as MemberExpression; string expStr = exp.ToString(); return expStr.Substring(expStr.IndexOf(".") + 1); }
希望以上的代码能帮助大家在表达式的应用方面有所帮助,谢谢!