一:什么是表達式樹
Expression我們稱為是表達式樹,是一種數據結構體,用於存儲需要計算,運算的一種結構,這種結構可以只是存儲,而不進行運算。通常表達式目錄樹是配合Lambda一起來使用的,lambda可以是匿名方法,當然也可以使用Expression來動態的創建!下面我們舉例來說明什么是表達式目錄樹。
先創建一個People的實體,下面會用到
/// <summary> /// 實體類 /// </summary> public class People { public int Age { get; set; } public string Name { get; set; } public int Id; }
我們可以通過下面創建表達式目錄樹,我們稱之為A種方式:
Expression<Func<People, bool>> lambda = x => x.Id.ToString().IndexOf("5") >= 0;
我們還可以使用Expression來動態創建,我們稱之為B種方式:
var peopleParam = Expression.Parameter(typeof(People), "x");//創建一個x,類型為people //得到x.Id MemberExpression idParam = Expression.Field(peopleParam, "Id"); //得到ToString方法 MethodInfo toStringWay = typeof(int).GetMethod("ToString", new Type[] { }); //得到IndexOf的方法,然后new Type[]這個代表是得到參數為string的一個方法 MethodInfo indexOfWay = typeof(string).GetMethod("IndexOf", new Type[] { typeof(string) }); //通過下面方法得到x.Id.ToString() MethodCallExpression tostringResult = Expression.Call(idParam, toStringWay, new Expression[] { }); //通過下面方法得到x.Id.ToString().IndexOf("5") ,MethodCallExpression繼承於Expression MethodCallExpression indexOfResult = Expression.Call(tostringResult, indexOfWay, new Expression[] { Expression.Constant("5") }); //x.Id.ToString().IndexOf("5")>=0 var lambdaBody = Expression.GreaterThanOrEqual(indexOfResult, Expression.Constant(0)); //得到x => x.Id.ToString().IndexOf("5") >= 0,后面的一個參數指的是x,如果有多個則指定多個 Expression<Func<People,bool>> lambdaResult = Expression.Lambda<Func<People, bool>>(lambdaBody, new ParameterExpression[] { peopleParam }); //通過lambdaResult.Compile()得到Func<People,bool>這樣的委托,然后Invoke是調用委托 bool result = lambdaResult.Compile().Invoke(new People() { Id = 155 });
A種和B種得到的結果是一致的,只不過第一種是通過lambda匿名方法來構建,第二種是通過動態的Expression來構建。另外下面的原理也是一樣的
//普通的Lambda表達式 Func<int,int,int> func = (x,y)=> x + y - 2; //表達式目錄樹的Lambda表達式聲明方式 Expression<Func<int, int, int>> expression = (x, y) => x + y - 2;
//表達式目錄樹的拼接方式實現 ParameterExpression parameterx = Expression.Parameter(typeof(int), "x"); ParameterExpression parametery = Expression.Parameter(typeof(int), "y"); ConstantExpression constantExpression = Expression.Constant(2, typeof(int)); BinaryExpression binaryAdd = Expression.Add(parameterx, parametery); BinaryExpression binarySubtract = Expression.Subtract(binaryAdd, constantExpression); Expression<Func<int, int, int>> expressionMosaic = Expression.Lambda<Func<int, int, int>>(binarySubtract, new ParameterExpression[] { parameterx, parametery });
int ResultLambda = func(5, 2); int ResultExpression = expression.Compile()(5, 2); int ResultMosaic = expressionMosaic.Compile()(5, 2); Console.WriteLine($"func:{ResultLambda}"); Console.WriteLine($"expression:{ResultExpression}"); Console.WriteLine($"expressionMosaic:{ResultMosaic}");
下面舉例說明以下Expression.Block
ParameterExpression varExpr = Expression.Variable(typeof(int), "x"); //add(int x); var ex1 = Expression.Assign(varExpr, Expression.Constant(1)); //x = 1; var ex1 = x; var ex2 = Expression.Add(ex1, Expression.Constant(5)); //var ex2 = ex1 + 5;//6 var ex4 = Expression.Add(ex2, Expression.Constant(9)); //var ex4 = ex2 + 9; //15 var ex5 = Expression.Add(ex4, Expression.Constant(8)); // var ex5 = ex4 + 8; //23 BlockExpression blockExpr = Expression.Block( new ParameterExpression[] { varExpr }, ex1, ex2, ex4, ex5 );
該代碼等效於,返回的結果都以最后一個Expression為主,則為ex5這個表達式
public int add(int x) { x = 1; var ex1 = x; var ex2 = ex1 + 5;//6 var ex4 = ex2 + 9; //15 var ex5 = ex4 + 8; //23 return ex5; //23 }
Expression.Block沒有返回值
{ Expression A = Expression.Constant("第一大"); Expression B = Expression.Constant("第二大"); Expression ex = Expression.GreaterThan(Expression.Constant(1), Expression.Constant(2)); var method = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }); var AM = Expression.Call(method, A); var BM = Expression.Call(method, B); var condition = Expression.IfThenElse(ex, AM, BM); var blockExpr = Expression.Block(condition); //IfThenElse是沒有返回值的 foreach (var expr in blockExpr.Expressions) Console.WriteLine(expr.ToString()); var lambdaExpression = Expression.Lambda<Action>(blockExpr).Compile(); lambdaExpression(); }
下圖是Expression的一些變量
二:表達式目錄樹與委托
Expression一般都是都是配合委托一起來使用的,比如和委托Action(沒有返回值),Func(至少有一個返回參數,且最后一個值為返回參數),Action,Func既可以直接傳入一個與之匹配的實體方法,又可以傳入lambda表達式這種匿名類(這種是聲明lambda表達式的一種快捷方式)。Expression,Action,Func關鍵詞是在.net 3.5之后出現的。Expression<Func<>>是可以轉成Func的(通過compile()這個方法轉換)。反過來則不行。我們可以理解為Func<>經過定義后,就無法改變它了。而表達式樹(Expression<Func<>>則是可以進行變更的。Lambda
使用lambda表達聲明表達式目錄樹的時候注意不能有{},即:
Func<int, int, int> func = (m, n) => m * n + 2;
上面這樣是可以的。但是下面這樣是不被允許的:
Expression<Func<int, int, int>> exp1 = (m, n) => { return m * n + 2; };//不能有語句體 只能是一行,不能有大括號
下面的例子來解析一下委托和表達式目錄樹

1 #region PrivateMethod 2 private static void Do1(Func<People, bool> func) 3 { 4 List<People> people = new List<People>(); 5 people.Where(func); 6 } 7 private static void Do1(Expression<Func<People, bool>> func) 8 { 9 List<People> people = new List<People>() 10 { 11 new People(){Id=4,Name="123",Age=4}, 12 new People(){Id=5,Name="234",Age=5}, 13 new People(){Id=6,Name="345",Age=6}, 14 }; 15 16 List<People> peopleList = people.Where(func.Compile()).ToList(); 17 } 18 19 private static IQueryable<People> GetQueryable(Expression<Func<People, bool>> func) 20 { 21 List<People> people = new List<People>() 22 { 23 new People(){Id=4,Name="123",Age=4}, 24 new People(){Id=5,Name="234",Age=5}, 25 new People(){Id=6,Name="345",Age=6}, 26 }; 27 28 return people.AsQueryable<People>().Where(func); 29 } 30 #endregion
然后調用的時候為如下:
1 Expression<Func<People, bool>> lambda1 = x => x.Age > 5; 2 Expression<Func<People, bool>> lambda2 = x => x.Id > 5; 3 Expression<Func<People, bool>> lambda3 = lambda1.And(lambda2); 4 Expression<Func<People, bool>> lambda4 = lambda1.Or(lambda2); 5 Expression<Func<People, bool>> lambda5 = lambda1.Not(); 6 Do1(lambda3); 7 Do1(lambda4); 8 Do1(lambda5);
三:使用Expression來進行不同對象的相同名字的屬性映射
如果我們有一個新的對象和People屬性基本上一致,如下:
/// <summary> /// 實體類Target /// PeopleDTO /// </summary> public class PeopleCopy { public int Age { get; set; } public string Name { get; set; } public int Id; }
現在我們想要把People的中Age,Name,Id等賦值給PeopleCopy,第一種我們直接想到的是硬編碼,然后如下:
People people = new People() { Id = 11, Name = "加菲貓", Age = 31 }; //PeopleCopy copy = (PeopleCopy)people; //這種強制轉換肯定是不行的 PeopleCopy peopleCopy = new PeopleCopy() { Id = people.Id, Name = people.Name, Age = people.Age };
但是如果有多個類型轉換,要寫N次,然后不同用且費力,所以我們會想到通用的方法,比如使用:【反射】,【序列化反序列化】,【緩存+表達式目錄】,【泛型+表達式目錄】,【AutoMapper】,我們可以用這五種方法都小試一下!
1:反射完成對象屬性映射
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExpressionDemo.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; } } }
2:使用序列化和反序列化來完成對象屬性映射:
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExpressionDemo.MappingExtend { /// <summary> /// 使用第三方序列化反序列化工具 /// /// 還有automapper /// </summary> public class SerializeMapper { /// <summary> /// 序列化反序列化方式 /// </summary> /// <typeparam name="TIn"></typeparam> /// <typeparam name="TOut"></typeparam> public static TOut Trans<TIn, TOut>(TIn tIn) { return JsonConvert.DeserializeObject<TOut>(JsonConvert.SerializeObject(tIn)); } } }
3:緩存+表達式目錄樹
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace ExpressionDemo.MappingExtend { /// <summary> /// 生成表達式目錄樹 緩存 /// </summary> public class ExpressionMapper { /// <summary> /// 字典緩存--hash分布 /// </summary> private static Dictionary<string, object> _Dic = new Dictionary<string, object>(); /// <summary> /// 字典緩存表達式樹 /// </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 = string.Format("funckey_{0}_{1}", 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); } } }
4:泛型+表達式目錄樹
1 using System; 2 using System.Collections.Generic; 3 using System.Linq.Expressions; 4 5 namespace ExpressionDemo.MappingExtend 6 { 7 /// <summary> 8 /// 生成表達式目錄樹 泛型緩存 9 /// </summary> 10 /// <typeparam name="TIn"></typeparam> 11 /// <typeparam name="TOut"></typeparam> 12 public class ExpressionGenericMapper<TIn, TOut>//Mapper`2 13 { 14 private static Func<TIn, TOut> _FUNC = null; 15 static ExpressionGenericMapper() 16 { 17 ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p"); 18 List<MemberBinding> memberBindingList = new List<MemberBinding>(); 19 foreach (var item in typeof(TOut).GetProperties()) 20 { 21 MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name)); //p.Age 22 MemberBinding memberBinding = Expression.Bind(item, property); //Age=p.Age 23 memberBindingList.Add(memberBinding); 24 } 25 foreach (var item in typeof(TOut).GetFields()) 26 { 27 MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name)); 28 MemberBinding memberBinding = Expression.Bind(item, property); 29 memberBindingList.Add(memberBinding); 30 } 31 //new PeopleCopy() {Age = p.Age, Name = p.Name, Id = p.Id} 32 MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray()); 33 //p => new PeopleCopy() {Age = p.Age, Name = p.Name, Id = p.Id} 34 Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] 35 { 36 parameterExpression 37 }); 38 _FUNC = lambda.Compile();//拼裝是一次性的 39 } 40 public static TOut Trans(TIn t) 41 { 42 return _FUNC(t); 43 } 44 } 45 }
5:使用.netFramwork框架自帶的AutoMapper,首先我們要nuget添加引用AutoMapper即可直接使用,具體代碼為:

1 using AutoMapper; 2 3 namespace ExpressionDemo.MappingExtend 4 { 5 public class AutoMapperTest 6 { 7 public static TOut Trans<TIn, TOut>(TIn tIn) 8 { 9 return Mapper.Instance.Map<TOut>(tIn); 10 } 11 } 12 }
五種方法我們分別調用一下,然后測試一下性能,代碼如下:

1 { 2 People people = new People() 3 { 4 Id = 11, 5 Name = "加菲貓", 6 Age = 31 7 }; 8 //使用AutoMapper之前必須要初始化對應的關系 9 Mapper.Initialize(x => x.CreateMap<People, PeopleCopy>()); 10 11 long common = 0; 12 long generic = 0; 13 long cache = 0; 14 long reflection = 0; 15 long serialize = 0; 16 long autoMapper = 0; 17 { 18 Stopwatch watch = new Stopwatch(); 19 watch.Start(); 20 for (int i = 0; i < 1000000; i++) 21 { 22 PeopleCopy peopleCopy = new PeopleCopy() 23 { 24 Id = people.Id, 25 Name = people.Name, 26 Age = people.Age 27 }; 28 } 29 watch.Stop(); 30 common = watch.ElapsedMilliseconds; 31 } 32 { 33 Stopwatch watch = new Stopwatch(); 34 watch.Start(); 35 for (int i = 0; i < 1000000; i++) 36 { 37 PeopleCopy peopleCopy = AutoMapperTest.Trans<People, PeopleCopy>(people); 38 } 39 watch.Stop(); 40 autoMapper = watch.ElapsedMilliseconds; 41 } 42 { 43 Stopwatch watch = new Stopwatch(); 44 watch.Start(); 45 for (int i = 0; i < 1000000; i++) 46 { 47 PeopleCopy peopleCopy = ReflectionMapper.Trans<People, PeopleCopy>(people); 48 } 49 watch.Stop(); 50 reflection = watch.ElapsedMilliseconds; 51 } 52 { 53 Stopwatch watch = new Stopwatch(); 54 watch.Start(); 55 for (int i = 0; i < 1000000; i++) 56 { 57 PeopleCopy peopleCopy = SerializeMapper.Trans<People, PeopleCopy>(people); 58 } 59 watch.Stop(); 60 serialize = watch.ElapsedMilliseconds; 61 } 62 { 63 Stopwatch watch = new Stopwatch(); 64 watch.Start(); 65 for (int i = 0; i < 1000000; i++) 66 { 67 PeopleCopy peopleCopy = ExpressionMapper.Trans<People, PeopleCopy>(people); 68 } 69 watch.Stop(); 70 cache = watch.ElapsedMilliseconds; 71 } 72 { 73 Stopwatch watch = new Stopwatch(); 74 watch.Start(); 75 for (int i = 0; i < 1000000; i++) 76 { 77 PeopleCopy peopleCopy = ExpressionGenericMapper<People, PeopleCopy>.Trans(people); 78 } 79 watch.Stop(); 80 generic = watch.ElapsedMilliseconds; 81 } 82 83 Console.WriteLine($"common = { common} ms"); 84 Console.WriteLine($"reflection = { reflection} ms"); 85 Console.WriteLine($"serialize = { serialize} ms"); 86 Console.WriteLine($"cache = { cache} ms"); 87 Console.WriteLine($"generic = { generic} ms"); 88 Console.WriteLine($"automapper = { autoMapper} ms"); 89 //性能比automapper還要高 90 }
運行結果如下:
通過結果發現:反射和序列化運用的時間最多,而我們驚奇的發現表達式目錄樹+泛型緩存比框架自帶的AutoMapper時間還短!有木有感覺超級膩害~!
四:ORM與表達式樹目錄的關系
我們平常項目中經常用到EF,其實都是繼承Queryable,然后我們使用的EF通常都會使用 var items = anserDo.GetAll().Where(x => x.OrganizationId == input.oid || input.oid == 0) ,where其實傳的就是表達式目錄樹。那我們來一步一步解析EF底層實現的具體邏輯。
lambada表達式上面說了能使用Expression來動態拼接,當然它還有一個神奇的功能,能動態的解耦。Expression有個類ExpressionVisitor
這個類中的Visit(Expression node)是解讀表達式的入口,然后能夠神奇的區分參數和方法體,然后將表達式調度到此類中更專用的訪問方法中,然后一層一層的解析下去,一直到最終的葉節點!
將表達式調度到此類中更專用的訪問方法中:我們來舉例說明:

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Linq.Expressions; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace ExpressionDemo.Visitor 9 { 10 public class OperationsVisitor : ExpressionVisitor 11 { 12 public Expression Modify(Expression expression) 13 { 14 return this.Visit(expression); 15 } 16 17 protected override Expression VisitBinary(BinaryExpression b) 18 { 19 if (b.NodeType == ExpressionType.Add) 20 { 21 Expression left = this.Visit(b.Left); 22 Expression right = this.Visit(b.Right); 23 return Expression.Subtract(left, right); 24 } 25 26 return base.VisitBinary(b); 27 } 28 29 protected override Expression VisitConstant(ConstantExpression node) 30 { 31 return base.VisitConstant(node); 32 } 33 } 34 }
下面調用:
1 { 2 //修改表達式目錄樹 3 Expression<Func<int, int, int>> exp = (m, n) => m * n + 2; 4 OperationsVisitor visitor = new OperationsVisitor(); 5 Expression expNew = visitor.Modify(exp); 6 }
visit這個這個方法能夠識別出來 m*n+2 是個二叉樹,會通過下面的圖然后一步一步的進行解析,如果遇到m*n 這會直接調用VisitBinary(BinaryExpression b)這個方法,如果遇到m或者n會調用VisitParameter(ParameterExpression node)這個方法,
如果遇到2常量則會調用VisitConstant(ConstantExpression node),這就是visit神奇的調度功能!
我們EF寫的where等lambda表達式,就是通過ExpressionVisitor這個類來反解析的!之前沒有學習過表達式目錄樹,以為ef本來就應該這樣寫,有沒有和我一樣認為的?
我們現在模擬寫一個lambda轉換sql的方法

1 using ExpressionDemo.DBExtend; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq.Expressions; 5 6 namespace ExpressionDemo.Visitor 7 { 8 public class ConditionBuilderVisitor : ExpressionVisitor 9 { 10 private Stack<string> _StringStack = new Stack<string>(); 11 12 public string Condition() 13 { 14 string condition = string.Concat(this._StringStack.ToArray()); 15 this._StringStack.Clear(); 16 return condition; 17 } 18 19 /// <summary> 20 /// 如果是二元表達式 21 /// </summary> 22 /// <param name="node"></param> 23 /// <returns></returns> 24 protected override Expression VisitBinary(BinaryExpression node) 25 { 26 if (node == null) throw new ArgumentNullException("BinaryExpression"); 27 28 this._StringStack.Push(")"); 29 base.Visit(node.Right);//解析右邊 30 this._StringStack.Push(" " + node.NodeType.ToSqlOperator() + " "); 31 base.Visit(node.Left);//解析左邊 32 this._StringStack.Push("("); 33 34 return node; 35 } 36 /// <summary> 37 /// 38 /// </summary> 39 /// <param name="node"></param> 40 /// <returns></returns> 41 protected override Expression VisitMember(MemberExpression node) 42 { 43 if (node == null) throw new ArgumentNullException("MemberExpression"); 44 this._StringStack.Push(" [" + node.Member.Name + "] "); 45 return node; 46 } 47 /// <summary> 48 /// 常量表達式 49 /// </summary> 50 /// <param name="node"></param> 51 /// <returns></returns> 52 protected override Expression VisitConstant(ConstantExpression node) 53 { 54 if (node == null) throw new ArgumentNullException("ConstantExpression"); 55 this._StringStack.Push(" '" + node.Value + "' "); 56 return node; 57 } 58 /// <summary> 59 /// 方法表達式 60 /// </summary> 61 /// <param name="m"></param> 62 /// <returns></returns> 63 protected override Expression VisitMethodCall(MethodCallExpression m) 64 { 65 if (m == null) throw new ArgumentNullException("MethodCallExpression"); 66 67 string format; 68 switch (m.Method.Name) 69 { 70 case "StartsWith": 71 format = "({0} LIKE {1}+'%')"; 72 break; 73 74 case "Contains": 75 format = "({0} LIKE '%'+{1}+'%')"; 76 break; 77 78 case "EndsWith": 79 format = "({0} LIKE '%'+{1})"; 80 break; 81 82 default: 83 throw new NotSupportedException(m.NodeType + " is not supported!"); 84 } 85 this.Visit(m.Object); 86 this.Visit(m.Arguments[0]); 87 string right = this._StringStack.Pop(); 88 string left = this._StringStack.Pop(); 89 this._StringStack.Push(String.Format(format, left, right)); 90 91 return m; 92 } 93 } 94 }

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Linq.Expressions; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace ExpressionDemo.DBExtend 9 { 10 internal static class SqlOperator 11 { 12 internal static string ToSqlOperator(this ExpressionType type) 13 { 14 switch (type) 15 { 16 case (ExpressionType.AndAlso): 17 case (ExpressionType.And): 18 return "AND"; 19 case (ExpressionType.OrElse): 20 case (ExpressionType.Or): 21 return "OR"; 22 case (ExpressionType.Not): 23 return "NOT"; 24 case (ExpressionType.NotEqual): 25 return "<>"; 26 case ExpressionType.GreaterThan: 27 return ">"; 28 case ExpressionType.GreaterThanOrEqual: 29 return ">="; 30 case ExpressionType.LessThan: 31 return "<"; 32 case ExpressionType.LessThanOrEqual: 33 return "<="; 34 case (ExpressionType.Equal): 35 return "="; 36 default: 37 throw new Exception("不支持該方法"); 38 } 39 40 } 41 } 42 }
然后調用的時候如下:

1 { 2 //修改表達式目錄樹 3 Expression<Func<int, int, int>> exp = (m, n) => m * n + 2; 4 OperationsVisitor visitor = new OperationsVisitor(); 5 Expression expNew = visitor.Modify(exp); 6 } 7 8 { 9 Expression<Func<People, bool>> lambda = x => x.Age > 5 && x.Id > 5 10 && x.Name.StartsWith("1") 11 && x.Name.EndsWith("1") 12 && x.Name.Contains("1"); 13 14 string sql = string.Format("Delete From [{0}] WHERE {1}" 15 , typeof(People).Name 16 , " [Age]>5 AND [ID] >5" 17 ); 18 ConditionBuilderVisitor vistor = new ConditionBuilderVisitor(); 19 vistor.Visit(lambda); 20 Console.WriteLine(vistor.Condition()); 21 } 22 { 23 Expression<Func<People, bool>> lambda = x => x.Age > 5 && x.Name == "A" || x.Id > 5; 24 ConditionBuilderVisitor vistor = new ConditionBuilderVisitor(); 25 vistor.Visit(lambda); 26 Console.WriteLine(vistor.Condition()); 27 } 28 { 29 Expression<Func<People, bool>> lambda = x => x.Age > 5 || (x.Name == "A" && x.Id > 5); 30 ConditionBuilderVisitor vistor = new ConditionBuilderVisitor(); 31 vistor.Visit(lambda); 32 Console.WriteLine(vistor.Condition()); 33 } 34 { 35 Expression<Func<People, bool>> lambda = x => (x.Age > 5 || x.Name == "A") && x.Id > 5; 36 ConditionBuilderVisitor vistor = new ConditionBuilderVisitor(); 37 vistor.Visit(lambda); 38 Console.WriteLine(vistor.Condition()); 39 }
目前Expression只支持ExpressionType的84種操作符Add, AndAlso等等,然后VisitMethodCall這個方法中表示lambda能解析出來的方法名字,如果需要可以自行修改會得到對應的sql語句的where條件!