最新設計請移步 輕量級表達式樹解析框架Faller http://m.survivalescaperooms.com/blqw/p/Faller.html
其實我也沒有深入了解表達式樹一些內在實現的原理,所以具體來說它到底是個什么東西我也不是很清楚,我的理解只是他是可以將'部分'委托構造成對象,方便我們對他進行解析; 雖然我沒有完全搞懂表達式樹,但這并不妨礙我使用它(如果以后有時間,我想我會更深入的去和它接觸一下)
對于Lamda表達式樹我的感覺是又愛又恨
書寫和閱讀方面,無疑是非常成功的,他大大的減少了書寫難度,增加了可讀性
但另一方面,在程序的性能上又是如此的糟糕
來看下面一個栗子:
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 兩個方法,唯一的不同,一個是委托,一個是表達式樹
同樣運行Where1和Where2 一萬次,Where2是0ms,Where1是57ms
也就是說從Func<User, bool>轉為Expression<Func<User, bool>>一萬次需要57ms
這對于我這樣一個追求性能的人來說,實在是有點難受!
到不至于不能接受,只有有點難受
但從另一方面我也在考慮,為什么像這樣的lamda不能直接預編譯成Expression呢?期待微軟的優化吧~
為什么我的標題中的框架為帶有引號?
因為我覺得這其實是一個偽框架
但他確實能幫助我們更好的解析Expression對象,或許應該把他稱之為解決方案或是別的
不過~管他呢!能用就行了
  剛才說了雖然我也沒有完全搞懂,但是有些東西還是應該知道的
比如:
第一個問題比較簡單

好了這里看到的就是所有`public`的子類(其實沒有公開的還有更多)
至于他們分別是干什么用的,每一個都有自己不同的用法,這里不可能一一說明了,下面的內容也只會涉及到一部分,其他就要自己慢慢研究了
舉個栗子:
BinaryExpression ----表示包含二元運算符的表達式
最基礎的用法就是它的三個屬性Left ,Right ,NodeType
Left 獲取二元運算的左操作數。
Right 獲取二元運算的右操作數。
NodeType 獲取此 Expression 的節點類型。
如 it = it.Name == "blqw"就是一個BinaryExpression
Left = it.Name
Right = "blqw"
NodeType = Equals
大概就是這么一個意思吧

嗯.允許我還是叫他框架吧,畢竟聽上去比較高端大氣上檔次啊

暫時是這樣

public class ParserArgs { public ParserArgs() { Builder = new StringBuilder(); } public StringBuilder Builder { get; private set; } public IList<ParameterExpression> Forms { get; set; } public readonly string[] FormsAlias = { "it", "A", "B", "C", "D", "E" }; }
IExpressionParser/// <summary> 表達式樹解析接口 /// </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> 表達式樹解析抽象泛型類 /// </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> 表達式類型枚舉 /// </summary> public enum ExpressionTypeCode { /// <summary> 未知類型表達式 /// </summary> Unknown = 0, /// <summary> 空表達式 null /// </summary> Null = 1, /// <summary> 表示包含二元運算符的表達式。 /// </summary> BinaryExpression = 2, /// <summary> 表示一個包含可在其中定義變量的表達式序列的塊。 /// </summary> BlockExpression = 3, /// <summary> 表示包含條件運算符的表達式。 /// </summary> ConditionalExpression = 4, /// <summary> 表示具有常量值的表達式。 /// </summary> ConstantExpression = 5, /// <summary> 發出或清除調試信息的序列點。 這允許調試器在調試時突出顯示正確的源代碼。 /// </summary> DebugInfoExpression = 6, /// <summary> 表示類型或空表達式的默認值。 /// </summary> DefaultExpression = 7, /// <summary> 表示動態操作。 /// </summary> DynamicExpression = 8, /// <summary> 表示無條件跳轉。 這包括 return 語句、break 和 continue 語句以及其他跳轉。 /// </summary> GotoExpression = 9, /// <summary> 表示編制屬性或數組的索引。 /// </summary> IndexExpression = 10, /// <summary> 表示將委托或 lambda 表達式應用于參數表達式列表的表達式。 /// </summary> InvocationExpression = 11, /// <summary> 表示一個標簽,可以將該標簽放置在任何 Expression 上下文中。 /// </summary> LabelExpression = 12, /// <summary> 描述一個 lambda 表達式。 這將捕獲與 .NET 方法體類似的代碼塊。 /// </summary> LambdaExpression = 13, /// <summary> 表示包含集合初始值設定項的構造函數調用。 /// </summary> ListInitExpression = 14, /// <summary> 表示無限循環。 可以使用“break”退出它。 /// </summary> LoopExpression = 15, /// <summary> 表示訪問字段或屬性。 /// </summary> MemberExpression = 16, /// <summary> 表示調用構造函數并初始化新對象的一個或多個成員。 /// </summary> MemberInitExpression = 17, /// <summary> 表示對靜態方法或實例方法的調用。 /// </summary> MethodCallExpression = 18, /// <summary> 表示創建新數組并可能初始化該新數組的元素。 /// </summary> NewArrayExpression = 19, /// <summary> 表示構造函數調用。 /// </summary> NewExpression = 20, /// <summary> 表示命名的參數表達式。 /// </summary> ParameterExpression = 21, /// <summary> 一個為變量提供運行時讀/寫權限的表達式。 /// </summary> RuntimeVariablesExpression = 22, /// <summary> 表示一個控制表達式,該表達式通過將控制傳遞到 SwitchCase 來處理多重選擇。 /// </summary> SwitchExpression = 23, /// <summary> 表示 try/catch/finally/fault 塊。 /// </summary> TryExpression = 24, /// <summary> 表示表達式和類型之間的操作。 /// </summary> TypeBinaryExpression = 25, /// <summary> 表示包含一元運算符的表達式。 /// </summary> UnaryExpression = 26, }

/// <summary> 解析器靜態對象 /// </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> 得到表達式類型的枚舉對象 </summary> /// <param name="expr"> 擴展對象: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> 得到當前表達式對象的解析組件 </summary> /// <param name="expr"> 擴展對象: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("未知的表達式類型", "expr"); case ExpressionTypeCode.Null: throw new ArgumentNullException("expr", "表達式為空"); default: throw new NotImplementedException("尚未實現" + 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); } }
首先將所有類型的表達式樹以枚舉的形式表現出來,1來是為了更直觀便于2是為了給他們編號
有了編號就可以方便的在數組或集合中給他們安排位置了
在Parser類中,放置一個靜態字段
private static readonly IExpressionParser[] Parsers = InitParsers();
在InitParsers方法中,使用反射查找當前命名空間下名稱為 枚舉名 + Parser 的類,如果有則實例化,并根據枚舉的值,在集合中保存
ps:枚舉名 + Parser 作為解析器的命名規則,僅僅是為了方便反射調用,Parsers[0] = new xxx() 這個依然是可以由后期調用綁定的
然后提供一個方法,用于獲取當前表達式對象對應的枚舉值
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; }
這里的方法我沒有選擇用反射來獲取枚舉值,還是基于對性能的考慮,這樣測試快5~10倍,有興趣的可以測試一下

public static ExpressionTypeCode GetCodeType(Expression expr) { if (expr == null) { return ExpressionTypeCode.Null; } ExpressionTypeCode tc; if (Enum.TryParse(expr.GetType().Name, out tc)) { return tc; } return ExpressionTypeCode.Unknown; }
得到枚舉之后,就可以按枚舉的值,從集合中獲取已經實例化的解析器為了方便調用,寫了一個方法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("未知的表達式類型", "expr"); case ExpressionTypeCode.Null: throw new ArgumentNullException("expr", "表達式為空"); default: throw new NotImplementedException("尚未實現" + codetype + "的解析"); } } return parser;}
得到解析器之后,就可以做愛做的事了,
好了我也有點累了,先這樣吧
干貨!表達式樹解析"框架"(2)
干貨!表達式樹解析"框架"(3)
新聞熱點
疑難解答