升级
然而,实践工作中,大家都会写相对复杂或者说多个条件的表达式。那么再采用上面的方式是无法确认表达式节点的类型进行转换的。我们可以添加一个Visit方法,根据 NodeType 转换成对应的Expression的类型,从而方法访问对应的属性进行表达式解析。
但是,重写之前,我们得了解一件事,既然叫表达式树,意味着在子节点里,还会有多个节点,如下图:
那么,我们假设,只要是 BinaryExpression(二元运算表达式)就会有多个子节,去访问子节点就是一个递归的过程,而终点就是 MemberExpression 和 ConstantExpression,对应字段名称和常量值的拼接。
下面是代码实现:
public class ExpressionTypeHelper { public StringBuilder GeWhere = new StringBuilder(100); public string Where { get { return GeWhere.ToString(); } } public void ResolveExpression(Expression<Func<Users, bool>> expression) { Visit(expression.Body); } public void Visit(Expression expression) { switch (expression.NodeType) { case ExpressionType.Constant: VisitConstantExpression(expression); break; case ExpressionType.MemberAccess: VisitMemberExpression(expression); break; case ExpressionType.Convert: VisitUnaryExpression(expression); break; default: VisitBinaryExpression(expression); break; } } public void VisitUnaryExpression(Expression expression) { var e = (UnaryExpression)expression; Visit(e.Operand); } public void VisitBinaryExpression(Expression expression) { var e = (BinaryExpression)expression; GeWhere.Append("("); Visit(e.Left); GeWhere.Append(e.NodeType.TransferExpressionType()); Visit(e.Right); GeWhere.Append(")"); } public void VisitConstantExpression(Expression expression) { var e = (ConstantExpression)expression; if (e.Type == typeof(string)) { GeWhere.Append("'" + e.Value + "'"); } else { GeWhere.Append(e.Value); } } public void VisitMemberExpression(Expression expression) { var e = (MemberExpression)expression; GeWhere.Append(e.Member.Name); } }
结果如下:
ExpressionVisitor的使用
一个基本的表达式解析思路基本实现了,但是!随着自己的orm的完善是不是这么多种的Expression类型都得在Visit方法添一遍,不是的。
ExpressionVisitor类是提供给我们的表达式树解析的帮助类,我们只要定义一个类继承ExpressionVisitor,实现一个 ResolveExpression 入口方法,重写
VisitBinary、VisitConstant、VisitMember方法,代码如下:
public class ExpressionTrasfer : ExpressionVisitor { public StringBuilder GeWhere = new StringBuilder(100); public string Where { get { return GeWhere.ToString(); } } public void ResolveExpression(Expression<Func<Users, bool>> expression) { Visit(expression.Body); } protected override Expression VisitBinary(BinaryExpression node) { GeWhere.Append("("); Visit(node.Left); GeWhere.Append(node.NodeType.TransferExpressionType()); Visit(node.Right); GeWhere.Append(")"); return node; } protected override Expression VisitConstant(ConstantExpression node) { if (node.Type == typeof(string)) { GeWhere.Append("'" + node.Value + "'"); } else if (node.Type == typeof(int)) { GeWhere.Append(node.Value); } return node; } protected override Expression VisitMember(MemberExpression node) { GeWhere.Append(node.Member.Name); return node; } }
结束
一个简单的表达式解析大致完成了,当然里面还有很多可以完善,例如值类型的判断,is 还是 = ,VisitMethodCall重写等等。原理就这样,实现我这里就不一一列举。
如对大家有帮助,麻烦请推荐,有不足请在下面评论提出,我会一一更改。