表達式目錄樹是一種語法樹,數據結構。數據都存儲在樹形結構中。
兩種方式,可以通過Lamada表達式聲明,也可以自己拼裝。
Lamada表達式聲明:
Expression
自己拼裝
ConstantExpression:常量值表達式
BinaryExpression:二元運算符表達式
ParameterExpression:參數表達式
ConstantExpression conLeft = Expression.Constant(345);
ConstantExpression conRight = Expression.Constant(456);
BinaryExpression binary = Expression.Add(conLeft, conRight);//345+456
Expression actExpression = Expression.Lambda(binary, null);//()=>345+456
//只能执行表示Lambda表达式的表达式目录树,即LambdaExpression或者Expression类型。如果表达式目录树不是表示Lambda表达式,需要调用Lambda方法创建一个新的表达式
actExpression.Compile()();//()=>345+456
通過ExpressionVisitor,遞歸查找所有的類型表達式,然後複寫父類的方法,對其進行相應的操作。
1) 自己寫的一個隊操作符操作的Visitor,首先必須的繼承自ExpressionVisitor抽象父類,來自 System.Linq.Expressions命名空間
public class OperationsVisitor:ExpressionVisitor
{
public Expression Modify(Expression node)
{
return base.Visit(node);
}
protected override Expression VisitBinary(BinaryExpression node)
{
if (node.NodeType==ExpressionType.Add)//如果二元表達式中間以加號連接
{
Expression left = Modify(node.Left);
Expression right= Modify(node.Right);
return Expression.Subtract(left,right);
}
return base.VisitBinary(node);
}
protected override Expression VisitParameter(ParameterExpression node)
{
return base.VisitParameter(node);
}
protected override Expression VisitConstant(ConstantExpression node)
{
return base.VisitConstant(node);
}
}
前端使用:
Expressionint,int,int>> expression = (x,y) => x * y + 3 + 2;
OperationsVisitor visitor = new OperationsVisitor();
Expression expNew = visitor.Modify(expression);
2) Sql中條件拼裝訪問器
public class ConditionBuilderVisitor:ExpressionVisitor
{
///
/// 棧:先進後出
///
private Stack<string> _stringStack = new Stack<string>();
///
/// 返回拼裝字符串
///
///
public string Condition()
{
string condition = string.Concat(this._stringStack.ToArray());
this._stringStack.Clear();
return condition;
}
///
/// 二元表達式
///
///
///
protected override Expression VisitBinary(BinaryExpression binaryExpression)
{
if (binaryExpression==null)
{
throw new ArgumentException("BinaryExpression");
}
this._stringStack.Push(")");
base.Visit(binaryExpression.Right);//解析右邊
this._stringStack.Push(" " + binaryExpression.NodeType.ToSqlOperator() + " ");
base.Visit(binaryExpression.Left);//解析左邊
this._stringStack.Push("(");
return binaryExpression;
}
///
/// 成員表達式
///
///
///
protected override Expression VisitMember(MemberExpression node)
{
if (node==null)
{
throw new ArgumentException("MemberExpression");
}
this._stringStack.Push(" [" + node.Member.Name + "] ");
return node;
}
///
/// 常量
///
///
///
protected override Expression VisitConstant(ConstantExpression constantExpression)
{
if (constantExpression==null)
{
throw new ArgumentException("ConstantExpression");
}
this._stringStack.Push("'"+ constantExpression.Value+"'");
return constantExpression;
}
protected override Expression VisitMethodCall(MethodCallExpression methodCall)
{
if (methodCall==null)
{
throw new ArgumentException("MethodCallExpression");
}
string format;
switch(methodCall.Method.Name)
{
case "StartsWith":
format = "({0} LIKE {1}+'%')";
break;
case "Contains":
format = "({0} LIKE '%'+{1}+'%')";
break;
case "EndsWith":
format = "({0} LIKE '%'+{1})";
break;
default:
throw new NotSupportedException(methodCall.NodeType + " is not supported!");
}
this.Visit(methodCall.Object);
this.Visit(methodCall.Arguments[0]);
string right = this._stringStack.Pop();
string left = this._stringStack.Pop();
this._stringStack.Push(String.Format(format, left, right));
return methodCall;
}
}
表達式類型的一個擴展方法:ToSqlOperator
internal static class SqlOperator
{
internal static string ToSqlOperator(this ExpressionType type)
{
switch(type)
{
case (ExpressionType.AndAlso):
case (ExpressionType.And):
return "AND";
case (ExpressionType.OrElse):
case (ExpressionType.Or):
return "OR";
case (ExpressionType.Not):
return "NOT";
case (ExpressionType.NotEqual):
return "<>";
case ExpressionType.GreaterThan:
return ">";
case ExpressionType.GreaterThanOrEqual:
return ">=";
case ExpressionType.LessThan:
return "<";
case ExpressionType.LessThanOrEqual:
return "<=";
case (ExpressionType.Equal):
return "=";
default:
throw new Exception("不支持该方法");
}
}
}
前端使用:
Expression> lambda = x => x.Age > 5 && x.Id > 5
&& x.Name.StartsWith("1")
&& x.Name.EndsWith("1")
&& x.Name.Contains("1");
//string sql = string.Format("Delete From [{0}] WHERE {1}"
// , typeof(People).Name
// , " [Age]>5 AND [ID] >5"
// );
ConditionBuilderVisitor vistor = new ConditionBuilderVisitor();
vistor.Visit(lambda);
Console.WriteLine(vistor.Condition());