關(guān)于我和表達(dá)式樹其實(shí)我也沒有深入了解表達(dá)式樹一些內(nèi)在實(shí)現(xiàn)的原理,所以具體來說它到底是個(gè)什么東西我也不是很清楚,我的理解只是他是可以將'部分'委托構(gòu)造成對(duì)象,方便我們對(duì)他進(jìn)行解析; 雖然我沒有完全搞懂表達(dá)式樹,但這并不妨礙我使用它(如果以后有時(shí)間,我想我會(huì)更深入的去和它接觸一下) Lamda + 表達(dá)式樹的性能瓶頸對(duì)于Lamda表達(dá)式樹我的感覺是又愛又恨 書寫和閱讀方面,無疑是非常成功的,他大大的減少了書寫難度,增加了可讀性 但另一方面,在程序的性能上又是如此的糟糕 來看下面一個(gè)栗子: static void Main() { Where1(u => u.Name == "1"); Where2(u => u.Name == "1"); } public static void Where1(Expression<Func<User, bool>> expr) { } public static void Where2(Func<User, bool> expr) { } 栗子中的 Where1 和 Where2 兩個(gè)方法,唯一的不同,一個(gè)是委托,一個(gè)是表達(dá)式樹 同樣運(yùn)行Where1和Where2 一萬次,Where2是0ms,Where1是57ms 也就是說從Func<User, bool>轉(zhuǎn)為Expression<Func<User, bool>>一萬次需要57ms 這對(duì)于我這樣一個(gè)追求性能的人來說,實(shí)在是有點(diǎn)難受! 到不至于不能接受,只有有點(diǎn)難受 但從另一方面我也在考慮,為什么像這樣的lamda不能直接預(yù)編譯成Expression呢?期待微軟的優(yōu)化吧~ 偽框架為什么我的標(biāo)題中的框架為帶有引號(hào)? 因?yàn)槲矣X得這其實(shí)是一個(gè)偽框架 但他確實(shí)能幫助我們更好的解析Expression對(duì)象,或許應(yīng)該把他稱之為解決方案或是別的 不過~管他呢!能用就行了 你應(yīng)該了解的Expression 剛才說了雖然我也沒有完全搞懂,但是有些東西還是應(yīng)該知道的
第一個(gè)問題比較簡單
好了這里看到的就是所有`public`的子類(其實(shí)沒有公開的還有更多) 至于他們分別是干什么用的,每一個(gè)都有自己不同的用法,這里不可能一一說明了,下面的內(nèi)容也只會(huì)涉及到一部分,其他就要自己慢慢研究了 舉個(gè)栗子:
大概就是這么一個(gè)意思吧 效果預(yù)覽
框架結(jié)構(gòu)嗯.允許我還是叫他框架吧,畢竟聽上去比較高端大氣上檔次啊
暫時(shí)是這樣
代碼
IExpressionParser
/// <summary> 表達(dá)式樹解析接口 /// </summary> public interface IExpressionParser { void Select(Expression expr, ParserArgs args); void Where(Expression expr, ParserArgs args); void GroupBy(Expression expr, ParserArgs args); void Having(Expression expr, ParserArgs args); void OrderBy(Expression expr, ParserArgs args); void Object(Expression expr, ParserArgs args); }
/// <summary> 表達(dá)式樹解析抽象泛型類 /// </summary> public abstract class ExpressionParser<T> : IExpressionParser where T : Expression { public abstract void Select(T expr, ParserArgs args); public abstract void Where(T expr, ParserArgs args); public abstract void GroupBy(T expr, ParserArgs args); public abstract void Having(T expr, ParserArgs args); public abstract void OrderBy(T expr, ParserArgs args); public abstract void Object(T expr, ParserArgs args); public void Select(Expression expr, ParserArgs args) { Select((T)expr, args); } public void Where(Expression expr, ParserArgs args) { Where((T)expr, args); } public void GroupBy(Expression expr, ParserArgs args) { GroupBy((T)expr, args); } public void Having(Expression expr, ParserArgs args) { Having((T)expr, args); } public void OrderBy(Expression expr, ParserArgs args) { OrderBy((T)expr, args); } public void Object(Expression expr, ParserArgs args) { Object((T)expr, args); } }
/// <summary> 表達(dá)式類型枚舉 /// </summary> public enum ExpressionTypeCode { /// <summary> 未知類型表達(dá)式 /// </summary> Unknown = 0, /// <summary> 空表達(dá)式 null /// </summary> Null = 1, /// <summary> 表示包含二元運(yùn)算符的表達(dá)式。 /// </summary> BinaryExpression = 2, /// <summary> 表示一個(gè)包含可在其中定義變量的表達(dá)式序列的塊。 /// </summary> BlockExpression = 3, /// <summary> 表示包含條件運(yùn)算符的表達(dá)式。 /// </summary> ConditionalExpression = 4, /// <summary> 表示具有常量值的表達(dá)式。 /// </summary> ConstantExpression = 5, /// <summary> 發(fā)出或清除調(diào)試信息的序列點(diǎn)。 這允許調(diào)試器在調(diào)試時(shí)突出顯示正確的源代碼。 /// </summary> DebugInfoExpression = 6, /// <summary> 表示類型或空表達(dá)式的默認(rèn)值。 /// </summary> DefaultExpression = 7, /// <summary> 表示動(dòng)態(tài)操作。 /// </summary> DynamicExpression = 8, /// <summary> 表示無條件跳轉(zhuǎn)。 這包括 return 語句、break 和 continue 語句以及其他跳轉(zhuǎn)。 /// </summary> GotoExpression = 9, /// <summary> 表示編制屬性或數(shù)組的索引。 /// </summary> IndexExpression = 10, /// <summary> 表示將委托或 lambda 表達(dá)式應(yīng)用于參數(shù)表達(dá)式列表的表達(dá)式。 /// </summary> InvocationExpression = 11, /// <summary> 表示一個(gè)標(biāo)簽,可以將該標(biāo)簽放置在任何 Expression 上下文中。 /// </summary> LabelExpression = 12, /// <summary> 描述一個(gè) lambda 表達(dá)式。 這將捕獲與 .NET 方法體類似的代碼塊。 /// </summary> LambdaExpression = 13, /// <summary> 表示包含集合初始值設(shè)定項(xiàng)的構(gòu)造函數(shù)調(diào)用。 /// </summary> ListInitExpression = 14, /// <summary> 表示無限循環(huán)。 可以使用“break”退出它。 /// </summary> LoopExpression = 15, /// <summary> 表示訪問字段或?qū)傩浴? /// </summary> MemberExpression = 16, /// <summary> 表示調(diào)用構(gòu)造函數(shù)并初始化新對(duì)象的一個(gè)或多個(gè)成員。 /// </summary> MemberInitExpression = 17, /// <summary> 表示對(duì)靜態(tài)方法或?qū)嵗椒ǖ恼{(diào)用。 /// </summary> MethodCallExpression = 18, /// <summary> 表示創(chuàng)建新數(shù)組并可能初始化該新數(shù)組的元素。 /// </summary> NewArrayExpression = 19, /// <summary> 表示構(gòu)造函數(shù)調(diào)用。 /// </summary> NewExpression = 20, /// <summary> 表示命名的參數(shù)表達(dá)式。 /// </summary> ParameterExpression = 21, /// <summary> 一個(gè)為變量提供運(yùn)行時(shí)讀/寫權(quán)限的表達(dá)式。 /// </summary> RuntimeVariablesExpression = 22, /// <summary> 表示一個(gè)控制表達(dá)式,該表達(dá)式通過將控制傳遞到 SwitchCase 來處理多重選擇。 /// </summary> SwitchExpression = 23, /// <summary> 表示 try/catch/finally/fault 塊。 /// </summary> TryExpression = 24, /// <summary> 表示表達(dá)式和類型之間的操作。 /// </summary> TypeBinaryExpression = 25, /// <summary> 表示包含一元運(yùn)算符的表達(dá)式。 /// </summary> UnaryExpression = 26, }
/// <summary> 解析器靜態(tài)對(duì)象 /// </summary> public static class Parser { private static readonly IExpressionParser[] Parsers = InitParsers(); static IExpressionParser[] InitParsers() { var codes = Enum.GetValues(typeof(ExpressionTypeCode)); var parsers = new IExpressionParser[codes.Length]; foreach (ExpressionTypeCode code in codes) { if (code.ToString().EndsWith("Expression")) { var type = Type.GetType(typeof(Parser).Namespace + code.ToString() + "Parser"); if (type != null) { parsers[(int)code] = (IExpressionParser)Activator.CreateInstance(type); } } } return parsers; } /// <summary> 得到表達(dá)式類型的枚舉對(duì)象 </summary> /// <param name="expr"> 擴(kuò)展對(duì)象:Expression </param> /// <returns> </returns> public static ExpressionTypeCode GetCodeType(Expression expr) { if (expr == null) { return ExpressionTypeCode.Null; } if (expr is BinaryExpression) { return ExpressionTypeCode.BinaryExpression; } if (expr is BlockExpression) { return ExpressionTypeCode.BlockExpression; } if (expr is ConditionalExpression) { return ExpressionTypeCode.ConditionalExpression; } if (expr is ConstantExpression) { return ExpressionTypeCode.ConstantExpression; } if (expr is DebugInfoExpression) { return ExpressionTypeCode.DebugInfoExpression; } if (expr is DefaultExpression) { return ExpressionTypeCode.DefaultExpression; } if (expr is DynamicExpression) { return ExpressionTypeCode.DynamicExpression; } if (expr is GotoExpression) { return ExpressionTypeCode.GotoExpression; } if (expr is IndexExpression) { return ExpressionTypeCode.IndexExpression; } if (expr is InvocationExpression) { return ExpressionTypeCode.InvocationExpression; } if (expr is LabelExpression) { return ExpressionTypeCode.LabelExpression; } if (expr is LambdaExpression) { return ExpressionTypeCode.LambdaExpression; } if (expr is ListInitExpression) { return ExpressionTypeCode.ListInitExpression; } if (expr is LoopExpression) { return ExpressionTypeCode.LoopExpression; } if (expr is MemberExpression) { return ExpressionTypeCode.MemberExpression; } if (expr is MemberInitExpression) { return ExpressionTypeCode.MemberInitExpression; } if (expr is MethodCallExpression) { return ExpressionTypeCode.MethodCallExpression; } if (expr is NewArrayExpression) { return ExpressionTypeCode.NewArrayExpression; } if (expr is NewExpression) { return ExpressionTypeCode.NewArrayExpression; } if (expr is ParameterExpression) { return ExpressionTypeCode.ParameterExpression; } if (expr is RuntimeVariablesExpression) { return ExpressionTypeCode.RuntimeVariablesExpression; } if (expr is SwitchExpression) { return ExpressionTypeCode.SwitchExpression; } if (expr is TryExpression) { return ExpressionTypeCode.TryExpression; } if (expr is TypeBinaryExpression) { return ExpressionTypeCode.TypeBinaryExpression; } if (expr is UnaryExpression) { return ExpressionTypeCode.UnaryExpression; } return ExpressionTypeCode.Unknown; } /// <summary> 得到當(dāng)前表達(dá)式對(duì)象的解析組件 </summary> /// <param name="expr"> 擴(kuò)展對(duì)象:Expression </param> /// <returns> </returns> public static IExpressionParser GetParser(Expression expr) { var codetype = GetCodeType(expr); var parser = Parsers[(int)codetype]; if (parser == null) { switch (codetype) { case ExpressionTypeCode.Unknown: throw new ArgumentException("未知的表達(dá)式類型", "expr"); case ExpressionTypeCode.Null: throw new ArgumentNullException("expr", "表達(dá)式為空"); default: throw new NotImplementedException("尚未實(shí)現(xiàn)" + codetype + "的解析"); } } return parser; } public static void Select(Expression expr, ParserArgs args) { GetParser(expr).Select(expr, args); } public static void Where(Expression expr, ParserArgs args) { GetParser(expr).Where(expr, args); } public static void GroupBy(Expression expr, ParserArgs args) { GetParser(expr).GroupBy(expr, args); } public static void Having(Expression expr, ParserArgs args) { GetParser(expr).Having(expr, args); } public static void OrderBy(Expression expr, ParserArgs args) { GetParser(expr).OrderBy(expr, args); } public static void Object(Expression expr, ParserArgs args) { GetParser(expr).Object(expr, args); } } 原理分解首先將所有類型的表達(dá)式樹以枚舉的形式表現(xiàn)出來,1來是為了更直觀便于2是為了給他們編號(hào) 有了編號(hào)就可以方便的在數(shù)組或集合中給他們安排位置了 初始化在Parser類中,放置一個(gè)靜態(tài)字段 private static readonly IExpressionParser[] Parsers = InitParsers(); 在InitParsers方法中,使用反射查找當(dāng)前命名空間下名稱為 枚舉名 + Parser 的類,如果有則實(shí)例化,并根據(jù)枚舉的值,在集合中保存 ps:枚舉名 + Parser 作為解析器的命名規(guī)則,僅僅是為了方便反射調(diào)用,Parsers[0] = new xxx() 這個(gè)依然是可以由后期調(diào)用綁定的 調(diào)用然后提供一個(gè)方法,用于獲取當(dāng)前表達(dá)式對(duì)象對(duì)應(yīng)的枚舉值 public static ExpressionTypeCode GetCodeType(Expression expr) { if (expr == null) { return ExpressionTypeCode.Null; } if (expr is BinaryExpression) { return ExpressionTypeCode.BinaryExpression; } if (expr is BlockExpression) { return ExpressionTypeCode.BlockExpression; } ... ... return ExpressionTypeCode.Unknown; } 這里的方法我沒有選擇用反射來獲取枚舉值,還是基于對(duì)性能的考慮,這樣測試快5~10倍,有興趣的可以測試一下
得到枚舉之后,就可以按枚舉的值,從集合中獲取已經(jīng)實(shí)例化的解析器為了方便調(diào)用,寫了一個(gè)方法GetParser public static IExpressionParser GetParser(Expression expr) { var codetype = GetCodeType(expr); var parser = Parsers[(int)codetype]; if (parser == null) { switch (codetype) { case ExpressionTypeCode.Unknown: throw new ArgumentException("未知的表達(dá)式類型", "expr"); case ExpressionTypeCode.Null: throw new ArgumentNullException("expr", "表達(dá)式為空"); default: throw new NotImplementedException("尚未實(shí)現(xiàn)" + codetype + "的解析"); } } return parser; } |
|
|