using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; namespace Hncore.Infrastructure.EntitiesExtension { internal class ConditionBuilder : ExpressionVisitor { private List m_arguments; private Stack m_conditionParts; public string Condition { get; private set; } public object[] Arguments { get; private set; } public void Build(Expression expression) { PartialEvaluator evaluator = new PartialEvaluator(); Expression evaluatedExpression = evaluator.Eval(expression); this.m_arguments = new List(); this.m_conditionParts = new Stack(); this.Visit(evaluatedExpression); this.Arguments = this.m_arguments.ToArray(); this.Condition = this.m_conditionParts.Count > 0 ? this.m_conditionParts.Pop() : null; } protected override Expression VisitBinary(BinaryExpression b) { if (b == null) return b; string opr; switch (b.NodeType) { case ExpressionType.Equal: opr = "="; break; case ExpressionType.NotEqual: opr = "<>"; break; case ExpressionType.GreaterThan: opr = ">"; break; case ExpressionType.GreaterThanOrEqual: opr = ">="; break; case ExpressionType.LessThan: opr = "<"; break; case ExpressionType.LessThanOrEqual: opr = "<="; break; case ExpressionType.AndAlso: opr = "AND"; break; case ExpressionType.OrElse: opr = "OR"; break; case ExpressionType.Add: opr = "+"; break; case ExpressionType.Subtract: opr = "-"; break; case ExpressionType.Multiply: opr = "*"; break; case ExpressionType.Divide: opr = "/"; break; default: throw new NotSupportedException(b.NodeType + "is not supported."); } this.Visit(b.Left); this.Visit(b.Right); string right = this.m_conditionParts.Pop(); string left = this.m_conditionParts.Pop(); string condition = String.Format("({0} {1} {2})", left, opr, right); this.m_conditionParts.Push(condition); return b; } protected override Expression VisitConstant(ConstantExpression c) { if (c == null) return c; this.m_arguments.Add(c.Value); this.m_conditionParts.Push(String.Format("{{{0}}}", this.m_arguments.Count - 1)); return c; } protected override Expression VisitMemberAccess(MemberExpression m) { if (m == null) return m; PropertyInfo propertyInfo = m.Member as PropertyInfo; if (propertyInfo == null) return m; this.m_conditionParts.Push(String.Format("[{0}]", propertyInfo.Name)); return m; } protected override Expression VisitMethodCall(MethodCallExpression m) { if (m == null) return m; string format; switch (m.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(m.NodeType + " is not supported!"); } this.Visit(m.Object); this.Visit(m.Arguments[0]); string right = this.m_conditionParts.Pop(); string left = this.m_conditionParts.Pop(); this.m_conditionParts.Push(String.Format(format, left, right)); return m; } } }