天天看點

C#進階--Expression詳解C#進階–Expression詳解

C#進階–Expression詳解

零、文章目錄

一、Expression是什麼

1、如何定義

  • Expression<Func<TSource, bool>>就是表達式目錄樹
  • Expression不能帶有大括号,隻能有一行代碼

2、和委托的差別

  • 在委托外面包裹一層Expression<>就是表達式目錄樹
  • 表達式目錄樹可以通過Compile()轉換成一個委托

3、Expression本質

  • 表達式目錄樹是一個類的封裝,描述了一個結構,有身體部分和參數部分
  • 身體部分分為左邊和右邊,内部描述了左邊和右邊之間的關系,可以不斷的往下拆分,類似于二叉樹
  • 表達式目錄樹展開後的每一個節點也是一個表達式目錄樹
Expression<Func<People, bool>> expression = p => p.Id == 10;
Func<People, bool> func = expression.Compile();
bool bResult = func.Invoke(new People()
{
    Id = 10,
    Name = "張三"
});
           

二、Expression動态拼裝

1、最基礎版本

Expression<Func<int>> expression = () => 123 + 234;
//常量表達式
ConstantExpression expression1 = Expression.Constant(123);
ConstantExpression expression2 = Expression.Constant(234);
//二進制表達式
BinaryExpression binaryExpression = Expression.Add(expression1, expression2);
Expression<Func<int>> expressionReslut = Expression.Lambda<Func<int>>(binaryExpression);
Func<int> func = expressionReslut.Compile();
int iResult = func.Invoke();
           

2、帶參數版本

Expression<Func<int, int>> expression1 = m => m + 1;
Func<int, int> func = expression1.Compile();
int iResult = func.Invoke(5);
//參數表達式
ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "m");
//常量表達式
ConstantExpression constant = Expression.Constant(1, typeof(int));
//二進制表達式
BinaryExpression addExpression = Expression.Add(parameterExpression, constant);
Expression<Func<int, int>> expression = Expression.Lambda<Func<int, int>>(addExpression, new ParameterExpression[1]
{
      parameterExpression
});
Func<int, int> func1 = expression.Compile();
int iResult1 = func1.Invoke(5);
           

3、帶有多個參數

Expression<Func<int, int, int>> expression = (m, n) => m * n + 2;
Func<int, int, int> func = expression.Compile();
int iResult = func.Invoke(10, 20);
//參數表達式
ParameterExpression parameterExpressionM = Expression.Parameter(typeof(int), "m");
ParameterExpression parameterExpressionN = Expression.Parameter(typeof(int), "n");
//二進制表達式
BinaryExpression multiply = Expression.Multiply(parameterExpressionM, parameterExpressionN);
//常量表達式
ConstantExpression constantExpression = Expression.Constant(2);
//二進制表達式
BinaryExpression plus = Expression.Add(multiply, constantExpression);
Expression<Func<int, int, int>> expression1 = Expression.Lambda<Func<int, int, int>>(plus, new ParameterExpression[2]
{
      parameterExpressionM,
      parameterExpressionN
});
Func<int, int, int> func1 = expression1.Compile();
int iResult1 = func1.Invoke(10, 20);
           

4、對象字段值比較

類似于這種比較複雜的,建議大家可以反編譯看看

Expression<Func<People, bool>> predicate = c => c.Id == 10;
Func<People, bool> func = predicate.Compile();
bool bResult = func.Invoke(new People()
{
    Id = 10
});

//參數表達式
ParameterExpression parameterExpression = Expression.Parameter(typeof(People), "c");
//反射擷取屬性
FieldInfo fieldId = typeof(People).GetField("Id");
//通過parameterExpression來擷取調用Id
MemberExpression idExp = Expression.Field(parameterExpression, fieldId);
//常量表達式
ConstantExpression constant10 = Expression.Constant(10, typeof(int));
//二進制表達式
BinaryExpression expressionExp = Expression.Equal(idExp, constant10);
Expression<Func<People, bool>> predicate1 = Expression.Lambda<Func<People, bool>>(expressionExp, new ParameterExpression[1]
{
            parameterExpression
});

Func<People, bool> func1 = predicate1.Compile();
bool bResult1 = func1.Invoke(new People()
{
    Id = 10
});
           

5、多條件

如果遇到很長的表達式目錄樹,拼裝建議從右往左拼裝

Expression<Func<People, bool>> predicate = c =>
    c.Id.ToString() == "10"
    && c.Name.Equals("張三")
    && c.Age > 35;
Func<People, bool> func = predicate.Compile();
bool bResult = func.Invoke(new People()
{
    Id = 10,
    Name = "張三",
    Age = 36
});

ParameterExpression parameterExpression = Expression.Parameter(typeof(People), "c");
//c.Age > 35
ConstantExpression constant35 = Expression.Constant(35);
PropertyInfo propAge = typeof(People).GetProperty("Age");
MemberExpression ageExp = Expression.Property(parameterExpression, propAge);
BinaryExpression cagExp = Expression.GreaterThan(ageExp, constant35);
//c.Name.Equals("張三")
ConstantExpression constantrichard = Expression.Constant("張三");
PropertyInfo propName = typeof(People).GetProperty("Name");
MemberExpression nameExp = Expression.Property(parameterExpression, propName);
MethodInfo equals = typeof(string).GetMethod("Equals", new Type[] { typeof(string) });
MethodCallExpression NameExp = Expression.Call(nameExp, equals, constantrichard);
//c.Id.ToString() == "10"
ConstantExpression constantExpression10 = Expression.Constant("10", typeof(string));
FieldInfo fieldId = typeof(People).GetField("Id");
var idExp = Expression.Field(parameterExpression, fieldId);
MethodInfo toString = typeof(int).GetMethod("ToString", new Type[0]);
var toStringExp = Expression.Call(idExp, toString, Array.Empty<Expression>());
var EqualExp = Expression.Equal(toStringExp, constantExpression10);
//c.Id.ToString() == "10"&& c.Name.Equals("張三")&& c.Age > 35
var plus = Expression.AndAlso(EqualExp, NameExp);
var exp = Expression.AndAlso(plus, cagExp);
Expression<Func<People, bool>> predicate1 = Expression.Lambda<Func<People, bool>>(exp, new ParameterExpression[1]
{
     parameterExpression
});
Func<People, bool> func1 = predicate1.Compile();
bool bResult1 = func1.Invoke(new People()
{
    Id = 10,
    Name = "張三",
    Age = 36
});
           

三、Expression應用之Mapper映射

需求:需要把People字段值映射到PeopleCopy字段

1、寫死

性能好,不靈活;不能共用

PeopleCopy peopleCopy0 = new PeopleCopy()
{
    Id = people.Id,
    Name = people.Name,
    Age = people.Age
};
           

2、反射

靈活,但是性能不好

using System;

namespace MyExpression.MappingExtend
{
    public class ReflectionMapper
    {
        /// <summary>
        /// 反射
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="tIn"></param>
        /// <returns></returns>
        public static TOut Trans<TIn, TOut>(TIn tIn)
        {
            TOut tOut = Activator.CreateInstance<TOut>();
            foreach (var itemOut in tOut.GetType().GetProperties())
            {
                var propIn = tIn.GetType().GetProperty(itemOut.Name);
                itemOut.SetValue(tOut, propIn.GetValue(tIn)); 
            }

            foreach (var itemOut in tOut.GetType().GetFields())
            {
                var fieldIn = tIn.GetType().GetField(itemOut.Name);
                itemOut.SetValue(tOut, fieldIn.GetValue(tIn)); 
            }
            return tOut;
        }
    }
}
           

調用

PeopleCopy peopleCopy1 = ReflectionMapper.Trans<People, PeopleCopy>(people);
           

3、序列化

靈活,但是性能不好

using Newtonsoft.Json;

namespace MyExpression.MappingExtend
{
    public class SerializeMapper
    {
        /// <summary>
        /// 序列化
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        public static TOut Trans<TIn, TOut>(TIn tIn)
        {
            string strJson = JsonConvert.SerializeObject(tIn); 
            return JsonConvert.DeserializeObject<TOut>(strJson);
        }
    }
}
           

調用

PeopleCopy peopleCopy2 = SerializeMapper.Trans<People, PeopleCopy>(people);
           

4、Expression動态拼接+普通緩存

  • 把People變成PeopleCopy的過程封裝在一個委托中,這個委托通過表達式目錄樹Compile出來,過程動态拼裝适應不同的類型
  • 第一次生成的時候,儲存一個委托在緩存中,如果第二次來,委托就可以直接從緩存中擷取到,直接運作委托,效率高
using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace MyExpression.MappingExtend
{    
    public class ExpressionMapper
    {
        /// <summary>
        /// 字典緩存,儲存的是委托,委托内部是轉換的動作
        /// </summary>
        private static Dictionary<string, object> _Dic = new Dictionary<string, object>();

        /// <summary>
        /// Expression動态拼接+普通緩存
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="tIn"></param>
        /// <returns></returns>
        public static TOut Trans<TIn, TOut>(TIn tIn)
        {
            string key = $"funckey_{typeof(TIn).FullName}_{typeof(TOut).FullName}";
            if (!_Dic.ContainsKey(key))
            {
                ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
                List<MemberBinding> memberBindingList = new List<MemberBinding>();
                foreach (var item in typeof(TOut).GetProperties())
                {
                    MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }
                foreach (var item in typeof(TOut).GetFields())
                {
                    MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }
                MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
                Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
                {
                    parameterExpression
                });
                Func<TIn, TOut> func = lambda.Compile();//拼裝是一次性的
                _Dic[key] = func;
            }
            return ((Func<TIn, TOut>)_Dic[key]).Invoke(tIn);
        }
    }
}
           

調用

PeopleCopy peopleCopy3 = ExpressionMapper.Trans<People, PeopleCopy>(people);
           

5、Expression動态拼接+泛型緩存

泛型緩存,就是為為每一組類型的組合,生成一個副本,性能最高

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace MyExpression.MappingExtend
{
    /// <summary>
    /// Expression動态拼接+泛型緩存
    /// </summary>
    /// <typeparam name="TIn"></typeparam>
    /// <typeparam name="TOut"></typeparam>
    public class ExpressionGenericMapper<TIn, TOut>//Mapper`2
    {
        private static Func<TIn, TOut> _FUNC = null;
        static ExpressionGenericMapper()
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
            List<MemberBinding> memberBindingList = new List<MemberBinding>();
            foreach (var item in typeof(TOut).GetProperties())
            {
                MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                MemberBinding memberBinding = Expression.Bind(item, property);
                memberBindingList.Add(memberBinding);
            }
            foreach (var item in typeof(TOut).GetFields())
            {
                MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                MemberBinding memberBinding = Expression.Bind(item, property);
                memberBindingList.Add(memberBinding);
            }
            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
            Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
            {
                    parameterExpression
            });
            _FUNC = lambda.Compile();//拼裝是一次性的
        }
        public static TOut Trans(TIn t)
        {
            return _FUNC(t);
        }
    }
}
           

調用

PeopleCopy peopleCopy4 = ExpressionGenericMapper<People, PeopleCopy>.Trans(people);
           

6、性能比較

Expression動态拼接+泛型緩存性能高,而且靈活

long common = 0;
long generic = 0;
long cache = 0;
long reflection = 0;
long serialize = 0;
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    for (int i = 0; i < 1_000_000; i++)
    {
        PeopleCopy peopleCopy = new PeopleCopy()
        {
            Id = people.Id,
            Name = people.Name,
            Age = people.Age
        };
    }
    watch.Stop();
    common = watch.ElapsedMilliseconds;
}
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    for (int i = 0; i < 1_000_000; i++)
    {
        PeopleCopy peopleCopy = ReflectionMapper.Trans<People, PeopleCopy>(people);
    }
    watch.Stop();
    reflection = watch.ElapsedMilliseconds;
}
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    for (int i = 0; i < 1_000_000; i++)
    {
        PeopleCopy peopleCopy = SerializeMapper.Trans<People, PeopleCopy>(people);
    }
    watch.Stop();
    serialize = watch.ElapsedMilliseconds;
}
{

    Stopwatch watch = new Stopwatch();
    watch.Start();
    for (int i = 0; i < 1_000_000; i++)
    {
        PeopleCopy peopleCopy = ExpressionMapper.Trans<People, PeopleCopy>(people);
    }
    watch.Stop();
    cache = watch.ElapsedMilliseconds;
}
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    for (int i = 0; i < 1_000_000; i++)
    {
        PeopleCopy peopleCopy = ExpressionGenericMapper<People, PeopleCopy>.Trans(people);
    }
    watch.Stop();
    generic = watch.ElapsedMilliseconds;
}

Console.WriteLine($"common = { common} ms");
Console.WriteLine($"reflection = { reflection} ms");
Console.WriteLine($"serialize = { serialize} ms");
Console.WriteLine($"cache = { cache} ms");
Console.WriteLine($"generic = { generic} ms");
           
運作結果
common = 32 ms
reflection = 1026 ms
serialize = 2510 ms
cache = 236 ms
generic = 31 ms
           

四、ExpressionVisitor解析Expression

1、Expression解析

  • Expression是通過通路者模式進行解析的,官方提供了ExpressionVisitor抽象類
  • ExpressionVisitor的Visit方法是解析表達式目錄樹的一個入口,Visit方法判斷Expression是一個什麼表達式目錄樹,走不同的細分方法進行進一步解析
  • ExpressionVisitor的VisitBinary方法是對二員表達式的解析,所有複雜的表達式都會拆解成二員表達式進行解析

2、Expression修改

自定義一個OperationsVisitor,繼承自ExpressionVisitor,複寫父類的VisitBinary方法,修改Expression的解析

OperationsVisitor定義
using System.Linq.Expressions;

namespace MyExpression
{
    /// <summary>
    /// 自定義Visitor
    /// </summary>
    public class OperationsVisitor : ExpressionVisitor
    {
        /// <summary>
        /// 覆寫父類方法;//二進制表達式的通路
        /// 把表達式目錄樹中相加改成相減,相乘改成相除
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        protected override Expression VisitBinary(BinaryExpression b)
        { 
            if (b.NodeType == ExpressionType.Add)//相加
            {
                Expression left = this.Visit(b.Left);
                Expression right = this.Visit(b.Right);
                return Expression.Subtract(left, right);//相減
            }
            else if (b.NodeType==ExpressionType.Multiply) //相乘
            {
                Expression left = this.Visit(b.Left);
                Expression right = this.Visit(b.Right);
                return Expression.Divide(left, right); //相除
            } 
            return base.VisitBinary(b);
        }
    }
}
           
Expression解析轉換
Expression<Func<int, int, int>> exp = (m, n) => m * n + 2;
Console.WriteLine(exp.ToString());
OperationsVisitor visitor = new OperationsVisitor();
Expression expNew = visitor.Visit(exp);
Console.WriteLine(expNew.ToString());
           
運作結果
(m, n) => ((m * n) + 2)
(m, n) => ((m / n) - 2)
           

3、封裝多條件連接配接擴充方法

擴充方法實作
/// <summary>
/// 合并表達式 And Or Not擴充方法
/// </summary>
public static class ExpressionExtend
{
    /// <summary>
    /// 合并表達式 expr1 AND expr2
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="expr1"></param>
    /// <param name="expr2"></param>
    /// <returns></returns>
    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        if (expr1 == null || expr2 == null)
        {
            throw new Exception("null不能處理");
        }
        ParameterExpression newParameter = Expression.Parameter(typeof(T), "x");
        NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);
        Expression left = visitor.Visit(expr1.Body);
        Expression right = visitor.Visit(expr2.Body);
        BinaryExpression body = Expression.And(left, right);
        return Expression.Lambda<Func<T, bool>>(body, newParameter);
    }

    /// <summary>
    /// 合并表達式 expr1 or expr2
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="expr1"></param>
    /// <param name="expr2"></param>
    /// <returns></returns>
    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        if (expr1 == null || expr2 == null)
        {
            throw new Exception("null不能處理");
        }
        ParameterExpression newParameter = Expression.Parameter(typeof(T), "x");
        NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);
        Expression left = visitor.Visit(expr1.Body);
        Expression right = visitor.Visit(expr2.Body);
        BinaryExpression body = Expression.Or(left, right);
        return Expression.Lambda<Func<T, bool>>(body, newParameter);
    }

    /// <summary>
    /// 表達式取非
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="expr"></param>
    /// <returns></returns>
    public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expr)
    {
        if (expr == null)
        {
            throw new Exception("null不能處理");
        }
        ParameterExpression newParameter = expr.Parameters[0];
        UnaryExpression body = Expression.Not(expr.Body);
        return Expression.Lambda<Func<T, bool>>(body, newParameter);
    }
}
           
自定義Visitor
internal class NewExpressionVisitor : ExpressionVisitor
{
    public ParameterExpression _NewParameter { get; private set; }
    public NewExpressionVisitor(ParameterExpression param)
    {
        this._NewParameter = param;
    }
    
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return this._NewParameter;
    }
}
           
資料過濾方法定義
/// <summary>
/// 篩選資料執行
/// </summary>
/// <param name="func"></param>
private static void Do(Expression<Func<People, bool>> func)
{
    List<People> people = new List<People>()
    {
        new People(){Id=4,Name="123",Age=4},
        new People(){Id=5,Name="234",Age=5},
        new People(){Id=6,Name="345",Age=6},
    };

    List<People> peopleList = people.Where(func.Compile()).ToList();
}
           
Expression拼接
Expression<Func<People, bool>> lambda1 = x => x.Age > 5;
Expression<Func<People, bool>> lambda2 = x => x.Id > 5;
Expression<Func<People, bool>> lambda3 = lambda1.And(lambda2);//且
Expression<Func<People, bool>> lambda4 = lambda1.Or(lambda2);//或
Expression<Func<People, bool>> lambda5 = lambda1.Not();//非
Do(lambda3);
Do(lambda4);
Do(lambda5);
           

五、ExpressionVisitor應用之ToSql

需求:實作ORM架構Expression映射成sql

自定義一個ConditionBuilderVisitor

繼承自ExpressionVisitor,複寫父類的方法,Expression解析過程中實作sql的拼接

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

namespace MyExpression
{
    public class ConditionBuilderVisitor : ExpressionVisitor
    {
        private Stack<string> _StringStack = new Stack<string>();

        /// <summary>
        /// 傳回拼裝好的sql條件表達式
        /// </summary>
        /// <returns></returns>
        public string Condition()
        {
            string condition = string.Concat(this._StringStack.ToArray());
            this._StringStack.Clear();
            return condition;
        }

        /// <summary>
        /// 如果是二進制表達式
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override Expression VisitBinary(BinaryExpression node)
        {
            if (node == null) throw new ArgumentNullException("BinaryExpression");

            this._StringStack.Push(")");
            base.Visit(node.Right);//解析右邊
            this._StringStack.Push(" " + ToSqlOperator(node.NodeType) + " ");
            base.Visit(node.Left);//解析左邊
            this._StringStack.Push("(");

            return node;
        }

        /// <summary>
        /// 解析屬性
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override Expression VisitMember(MemberExpression node)
        {
            if (node == null) throw new ArgumentNullException("MemberExpression");
            if (node.Expression is ConstantExpression)
            {
                var value1 = this.InvokeValue(node);
                var value2 = this.ReflectionValue(node);
                this._StringStack.Push("'" + value2 + "'");
            }
            else
            {
                this._StringStack.Push(" [" + node.Member.Name + "] ");
            }
            return node;
        }

        private string ToSqlOperator(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("不支援該方法");
            }
        }

        private object InvokeValue(MemberExpression member)
        {
            var objExp = Expression.Convert(member, typeof(object));//struct需要
            return Expression.Lambda<Func<object>>(objExp).Compile().Invoke();
        }

        private object ReflectionValue(MemberExpression member)
        {
            var obj = (member.Expression as ConstantExpression).Value;
            return (member.Member as FieldInfo).GetValue(obj);
        }

        /// <summary>
        /// 常量表達式
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override Expression VisitConstant(ConstantExpression node)
        {
            if (node == null) throw new ArgumentNullException("ConstantExpression");
            this._StringStack.Push("" + node.Value + "");
            return node;
        }
        /// <summary>
        /// 方法表達式
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        protected override Expression VisitMethodCall(MethodCallExpression m)
        {
            if (m == null) throw new ArgumentNullException("MethodCallExpression");

            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._StringStack.Pop();
            string left = this._StringStack.Pop();
            this._StringStack.Push(String.Format(format, left, right));
            return m;
        }
    }
}
           
ConstantSqlString泛型緩存緩存生成的sql
using System;
using System.Linq;

namespace MyExpression
{
    public class ConstantSqlString<T>
    {
        /// <summary>
        /// 泛型緩存,一個類型一個緩存
        /// </summary>
        private static string FindSql = null;

        /// <summary>
        /// 擷取查詢sql
        /// </summary>
        static ConstantSqlString()
        {
            Type type = typeof(T);
            FindSql = $"Select {string.Join(',', type.GetProperties().Select(c => $"[{c.Name}]").ToList())} from {type.Name}";
        }

        /// <summary>
        /// 擷取查詢sql+條件篩選
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static string GetQuerySql(string exp)
        {
            return $"{FindSql} where {exp}";
        }
    }
}
           
普通多條件
Expression<Func<People, bool>> lambda = x => x.Age > 5
                                             && x.Id > 5
                                             && x.Name.StartsWith("1") //  like '1%'
                                             && x.Name.EndsWith("1") //  like '%1'
                                             && x.Name.Contains("1");//  like '%1%' 
ConditionBuilderVisitor vistor = new ConditionBuilderVisitor();
vistor.Visit(lambda);
string sql = ConstantSqlString<People>.GetQuerySql(vistor.Condition());
Console.WriteLine(sql);
           
外部參數變量
string name = "AAA";
Expression<Func<People, bool>> lambda = x => x.Age > 5 && x.Name == name || x.Id > 5;
ConditionBuilderVisitor vistor = new ConditionBuilderVisitor();
vistor.Visit(lambda);
string sql = ConstantSqlString<People>.GetQuerySql(vistor.Condition());
Console.WriteLine(sql);
           
内部常量多條件
Expression<Func<People, bool>> lambda = x => x.Age > 5 || (x.Name == "A" && x.Id > 5);
ConditionBuilderVisitor vistor = new ConditionBuilderVisitor();
vistor.Visit(lambda);
string sql = ConstantSqlString<People>.GetQuerySql(vistor.Condition());
Console.WriteLine(sql);
           
運作結果
Select [Age],[Name] from People where ((((( [Age]  > 5) AND ( [Id]  > 5)) AND ( [Name]  LIKE '1%')) AND ( [Name]  LIKE '%1')) AND ( [Name]  LIKE '%1%'))
Select [Age],[Name] from People where ((( [Age]  > 5) AND ( [Name]  = 'AAA')) OR ( [Id]  > 5))
Select [Age],[Name] from People where (( [Age]  > 5) OR (( [Name]  = A) AND ( [Id]  > 5)))