CSharp基础-遍历/修改表达式树

遍历/修改表达式树

可以使用 ExpressionVisitor 类遍历现有表达式树,以及复制它访问的每个节点。

表达式的遍历

参考:

ExpressionType

Expression

ExpressionVisitor

表达式类型 表达式操作节点类型 ExpressionVisitor类访问方法
UnaryExpression ExpressionType.ArrayLength
ExpressionType.ArrayLength
ExpressionType.Convert
ExpressionType.ConvertChecked
ExpressionType.Decrement
ExpressionType.Increment
ExpressionType.Negate
ExpressionType.NegateChecked
ExpressionType.Not
ExpressionType.NotEqual
ExpressionType.Quote
ExpressionType.TypeAs
VisitUnary(UnaryExpression)
BinaryExpression ExpressionType.Add
ExpressionType.AddAssign
ExpressionType.AddAssignChecked
ExpressionType.AddChecked
ExpressionType.And
ExpressionType.AndAlso
ExpressionType.AndAssign
ExpressionType.ArrayIndex
ExpressionType.Assign
ExpressionType.Coalesce
ExpressionType.Divide
ExpressionType.DivideAssign
ExpressionType.Equal
ExpressionType.GreaterThan
ExpressionType.GreaterThanOrEqual
ExpressionType.LessThan
ExpressionType.LessThanOrEqual
ExpressionType.Modulo
ExpressionType.ModuloAssign
ExpressionType.Multiply
ExpressionType.MultiplyAssign
ExpressionType.NotEqual
ExpressionType.Or
ExpressionType.OrElse
ExpressionType.Subtract
VisitBinary(BinaryExpression)
BlockExpression ExpressionType.Block VisitBlock(BlockExpression)
ConditionalExpression ExpressionType.Conditional VisitConditional(ConditionalExpression)
ConstantExpression ExpressionType.Constant VisitConstant(ConstantExpression)
ParameterExpression ExpressionType.Parameter VisitParameter(ParameterExpression)
MemberExpression ExpressionType.MemberAccess VisitMember(MemberExpression)
MemberInitExpression ExpressionType.MemberInit VisitMemberInit(MemberInitExpression)
MethodCallExpression ExpressionType.Call VisitMethodCall(MethodCallExpression)
LambdaExpression ExpressionType.Lambda VisitLambda()
NewExpression ExpressionType.New VisitNew(NewExpression)
NewArrayExpression ExpressionType.NewArrayBounds
ExpressionType.NewArrayInit
VisitNewArray(NewArrayExpression)
InvocationExpression ExpressionType.Invoke VisitInvocation(InvocationExpression)
ListInitExpression ExpressionType.ListInit VisitListInit(ListInitExpression)
TypeBinaryExpression ExpressionType.TypeIs VisitTypeBinary(TypeBinaryExpression)

扩展IQueryable的Where方法,根据输入的查询条件来构造SQL语句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
internal class Program
{
private static void Main(string[] args)
{
List<User> myUsers = new List<User>();
var userSql = myUsers.AsQueryable().Where(u => u.Age > 2);
Console.WriteLine(userSql);
// SELECT * FROM (SELECT * FROM User) AS T WHERE (Age>2)

List<User> myUsers2 = new List<User>();
var userSql2 = myUsers2.AsQueryable().Where(u => u.Name == "QueryExtension");
Console.WriteLine(userSql2);
//SELECT * FROM (SELECT * FROM USER) AS T WHERE (Name='QueryExtension')

Console.ReadKey();
}
}

public class User
{
public string Name { get; set; }
public int Age { get; set; }
}

public static class QueryExtensions
{
public static string Where<TSource>(this IQueryable<TSource> source,
Expression<Func<TSource, bool>> predicate)
{
var expression = Expression.Call(null, ((MethodInfo)MethodBase.GetCurrentMethod())
.MakeGenericMethod(new Type[] { typeof(TSource) }),
new Expression[] { source.Expression, Expression.Quote(predicate) });

var translator = new QueryTranslator();
return translator.Translate(expression);
}
}

internal class QueryTranslator : ExpressionVisitor
{
private StringBuilder sb;

internal string Translate(Expression expression)
{
this.sb = new StringBuilder();
this.Visit(expression);
return this.sb.ToString();
}

private static Expression StripQuotes(Expression e)
{
while (e.NodeType == ExpressionType.Quote)
{
e = ((UnaryExpression)e).Operand;
}
return e;
}

protected override Expression VisitMethodCall(MethodCallExpression m)
{
if (m.Method.DeclaringType == typeof(QueryExtensions) && m.Method.Name == "Where")
{
sb.Append("SELECT * FROM (");
this.Visit(m.Arguments[0]);
sb.Append(") AS T WHERE ");
LambdaExpression lambda = (LambdaExpression)StripQuotes(m.Arguments[1]);
this.Visit(lambda.Body);
return m;
}
throw new NotSupportedException(string.Format("方法{0}不支持", m.Method.Name));
}

protected override Expression VisitUnary(UnaryExpression u)
{
switch (u.NodeType)
{
case ExpressionType.Not:
sb.Append(" NOT ");
this.Visit(u.Operand);
break;

default:
throw new NotSupportedException(string.Format("运算{0}不支持", u.NodeType));
}
return u;
}

protected override Expression VisitBinary(BinaryExpression b)
{
sb.Append("(");
this.Visit(b.Left);
switch (b.NodeType)
{
case ExpressionType.And:
sb.Append(" AND ");
break;

case ExpressionType.Or:
sb.Append(" OR");
break;

case ExpressionType.Equal:
sb.Append(" = ");
break;

case ExpressionType.NotEqual:
sb.Append(" <> ");
break;

case ExpressionType.LessThan:
sb.Append(" < ");
break;

case ExpressionType.LessThanOrEqual:
sb.Append(" <= ");
break;

case ExpressionType.GreaterThan:
sb.Append(" > ");
break;

case ExpressionType.GreaterThanOrEqual:
sb.Append(" >= ");
break;

default:
throw new NotSupportedException(string.Format("运算符{0}不支持", b.NodeType));
}
this.Visit(b.Right);
sb.Append(")");
return b;
}

protected override Expression VisitConstant(ConstantExpression c)
{
IQueryable q = c.Value as IQueryable;
if (q != null)
{
// 我们假设我们那个Queryable就是对应的表
sb.Append("SELECT * FROM ");
sb.Append(q.ElementType.Name);
}
else if (c.Value == null)
{
sb.Append("NULL");
}
else
{
switch (Type.GetTypeCode(c.Value.GetType()))
{
case TypeCode.Boolean:
sb.Append(((bool)c.Value) ? 1 : 0);
break;

case TypeCode.String:
sb.Append("'");
sb.Append(c.Value);
sb.Append("'");
break;

case TypeCode.Object:
throw new NotSupportedException(string.Format("常量{0}不支持", c.Value));
default:
sb.Append(c.Value);
break;
}
}
return c;
}

protected override Expression VisitMember(MemberExpression m)
{
if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter)
{
sb.Append(m.Member.Name);
return m;
}
throw new NotSupportedException(string.Format("成员{0}不支持", m.Member.Name));
}
}

修改表达式树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class OperationsVisitor : ExpressionVisitor
{
public Expression Modify(Expression expression)
{
return this.Visit(expression);
}

protected override Expression VisitBinary(BinaryExpression b)
{
if (b.NodeType == ExpressionType.Add)
{
Expression left = this.Visit(b.Left); // // 或b.Left
Expression right = this.Visit(b.Right); // 或b.Right
return Expression.Subtract(left,right);
}

return base.VisitBinary(b);
}
}

static void Main(string[] args)
{
Expression<Func<int, int, int>> lambda = (a, b) => a + b * 2;

var operationsVisitor = new OperationsVisitor();
Expression modifyExpression = operationsVisitor.Modify(lambda);

Console.WriteLine(modifyExpression.ToString());
}

参考:

表达式树

ExpressionVisitor

System.Linq.Expressions

由浅入深表达式树(二)遍历表达式树