最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html

关于我和表达式树

  其实我也没有深入了解表达式树一些内在实现的原理,所以具体来说它到底是个什么东西我也不是很清楚,我的理解只是他是可以将'部分'委托构造成对象,方便我们对他进行解析; 虽然我没有完全搞懂表达式树,但这并不妨碍我使用它(如果以后有时间,我想我会更深入的去和它接触一下)

Lamda + 表达式树的性能瓶颈

  对于Lamda表达式树我的感觉是又爱又恨

  书写和阅读方面,无疑是非常成功的,他大大的减少了书写难度,增加了可读性

  但另一方面,在程序的性能上又是如此的糟糕

  来看下面一个栗子:

  1. static void Main()
  2. {
  3. Where1(u => u.Name == "");
  4. Where2(u => u.Name == "");
  5. }
  6.  
  7. public static void Where1(Expression<Func<User, bool>> expr)
  8. {
  9.  
  10. }
  11.  
  12. public static void Where2(Func<User, bool> expr)
  13. {
  14.  
  15. }

  栗子中的 Where1 和 Where2 两个方法,唯一的不同,一个是委托,一个是表达式树

  同样运行Where1和Where2 一万次,Where2是0ms,Where1是57ms

  也就是说从Func<User, bool>转为Expression<Func<User, bool>>一万次需要57ms

  这对于我这样一个追求性能的人来说,实在是有点难受!

  到不至于不能接受,只有有点难受

  但从另一方面我也在考虑,为什么像这样的lamda不能直接预编译成Expression呢?期待微软的优化吧~

伪框架

  为什么我的标题中的框架为带有引号?

  因为我觉得这其实是一个伪框架

  但他确实能帮助我们更好的解析Expression对象,或许应该把他称之为解决方案或是别的

  不过~管他呢!能用就行了

你应该了解的Expression

  刚才说了虽然我也没有完全搞懂,但是有些东西还是应该知道的
比如:

  • 以Expression作为基类的子类一共有多少个
  • 他们分别是干什么的

  第一个问题比较简单

  1. 现在在vs中敲下 System.Linq.Expressions.Expression
  2. 然后按F1
  3. 如果顺利的话,你现在已经打开了"MSDN"
  4. 如果没有的话就手动点一下吧
  5. 然后滚动到屏幕最下面

  

  好了这里看到的就是所有`public`的子类(其实没有公开的还有更多)

  至于他们分别是干什么用的,每一个都有自己不同的用法,这里不可能一一说明了,下面的内容也只会涉及到一部分,其他就要自己慢慢研究了

  举个栗子:

BinaryExpression ----表示包含二元运算符的表达式

最基础的用法就是它的三个属性Left ,Right ,NodeType 
Left 获取二元运算的左操作数。
Right 获取二元运算的右操作数。
NodeType 获取此 Expression 的节点类型。
it = it.Name == "blqw"就是一个BinaryExpression
Left = it.Name
Right = "blqw"
NodeType = Equals

  大概就是这么一个意思吧

效果预览

框架结构

  嗯.允许我还是叫他框架吧,毕竟听上去比较高端大气上档次啊

  暂时是这样

  • Parsers文件夹里面的是具体对应每一种表达式树的解析的具体实现
  • ExpressionParser     表达式树解析器抽象基类,实现IExpressionParser
  • ExpressionTypeCode   枚举,枚举了所有的类型的表达式树
  • IExpressionParser    表达式树解析器接口
  • Parser          调用解析器的静态对象,也可以看作入口或工厂,根据表达式树类型调用具体类
  • ParserArgs        解析器参数,在解析表达式树的方法中保持传递,可以保存解析中所使用的参数和保存解析结果

代码

  1. public class ParserArgs
  2. {
  3. public ParserArgs()
  4. {
  5. Builder = new StringBuilder();
  6. }
  7.  
  8. public StringBuilder Builder { get; private set; }
  9.  
  10. public IList<ParameterExpression> Forms { get; set; }
  11.  
  12. public readonly string[] FormsAlias = { "it", "A", "B", "C", "D", "E" };
  13. }

ParserArgs

  1. IExpressionParser
  1. /// <summary> 表达式树解析接口
  2. /// </summary>
  3. public interface IExpressionParser
  4. {
  5. void Select(Expression expr, ParserArgs args);
  6. void Where(Expression expr, ParserArgs args);
  7. void GroupBy(Expression expr, ParserArgs args);
  8. void Having(Expression expr, ParserArgs args);
  9. void OrderBy(Expression expr, ParserArgs args);
  10. void Object(Expression expr, ParserArgs args);
  11. }
  1. /// <summary> 表达式树解析抽象泛型类
  2. /// </summary>
  3. public abstract class ExpressionParser<T> : IExpressionParser
  4. where T : Expression
  5. {
  6. public abstract void Select(T expr, ParserArgs args);
  7. public abstract void Where(T expr, ParserArgs args);
  8. public abstract void GroupBy(T expr, ParserArgs args);
  9. public abstract void Having(T expr, ParserArgs args);
  10. public abstract void OrderBy(T expr, ParserArgs args);
  11. public abstract void Object(T expr, ParserArgs args);
  12.  
  13. public void Select(Expression expr, ParserArgs args)
  14. {
  15. Select((T)expr, args);
  16. }
  17.  
  18. public void Where(Expression expr, ParserArgs args)
  19. {
  20. Where((T)expr, args);
  21. }
  22.  
  23. public void GroupBy(Expression expr, ParserArgs args)
  24. {
  25. GroupBy((T)expr, args);
  26. }
  27.  
  28. public void Having(Expression expr, ParserArgs args)
  29. {
  30. Having((T)expr, args);
  31. }
  32.  
  33. public void OrderBy(Expression expr, ParserArgs args)
  34. {
  35. OrderBy((T)expr, args);
  36. }
  37.  
  38. public void Object(Expression expr, ParserArgs args)
  39. {
  40. Object((T)expr, args);
  41. }
  42. }

ExpressionParser

  1. /// <summary> 表达式类型枚举
  2. /// </summary>
  3. public enum ExpressionTypeCode
  4. {
  5. /// <summary> 未知类型表达式
  6. /// </summary>
  7. Unknown = ,
  8. /// <summary> 空表达式 null
  9. /// </summary>
  10. Null = ,
  11. /// <summary> 表示包含二元运算符的表达式。
  12. /// </summary>
  13. BinaryExpression = ,
  14. /// <summary> 表示一个包含可在其中定义变量的表达式序列的块。
  15. /// </summary>
  16. BlockExpression = ,
  17. /// <summary> 表示包含条件运算符的表达式。
  18. /// </summary>
  19. ConditionalExpression = ,
  20. /// <summary> 表示具有常量值的表达式。
  21. /// </summary>
  22. ConstantExpression = ,
  23. /// <summary> 发出或清除调试信息的序列点。 这允许调试器在调试时突出显示正确的源代码。
  24. /// </summary>
  25. DebugInfoExpression = ,
  26. /// <summary> 表示类型或空表达式的默认值。
  27. /// </summary>
  28. DefaultExpression = ,
  29. /// <summary> 表示动态操作。
  30. /// </summary>
  31. DynamicExpression = ,
  32. /// <summary> 表示无条件跳转。 这包括 return 语句、break 和 continue 语句以及其他跳转。
  33. /// </summary>
  34. GotoExpression = ,
  35. /// <summary> 表示编制属性或数组的索引。
  36. /// </summary>
  37. IndexExpression = ,
  38. /// <summary> 表示将委托或 lambda 表达式应用于参数表达式列表的表达式。
  39. /// </summary>
  40. InvocationExpression = ,
  41. /// <summary> 表示一个标签,可以将该标签放置在任何 Expression 上下文中。
  42. /// </summary>
  43. LabelExpression = ,
  44. /// <summary> 描述一个 lambda 表达式。 这将捕获与 .NET 方法体类似的代码块。
  45. /// </summary>
  46. LambdaExpression = ,
  47. /// <summary> 表示包含集合初始值设定项的构造函数调用。
  48. /// </summary>
  49. ListInitExpression = ,
  50. /// <summary> 表示无限循环。 可以使用“break”退出它。
  51. /// </summary>
  52. LoopExpression = ,
  53. /// <summary> 表示访问字段或属性。
  54. /// </summary>
  55. MemberExpression = ,
  56. /// <summary> 表示调用构造函数并初始化新对象的一个或多个成员。
  57. /// </summary>
  58. MemberInitExpression = ,
  59. /// <summary> 表示对静态方法或实例方法的调用。
  60. /// </summary>
  61. MethodCallExpression = ,
  62. /// <summary> 表示创建新数组并可能初始化该新数组的元素。
  63. /// </summary>
  64. NewArrayExpression = ,
  65. /// <summary> 表示构造函数调用。
  66. /// </summary>
  67. NewExpression = ,
  68. /// <summary> 表示命名的参数表达式。
  69. /// </summary>
  70. ParameterExpression = ,
  71. /// <summary> 一个为变量提供运行时读/写权限的表达式。
  72. /// </summary>
  73. RuntimeVariablesExpression = ,
  74. /// <summary> 表示一个控制表达式,该表达式通过将控制传递到 SwitchCase 来处理多重选择。
  75. /// </summary>
  76. SwitchExpression = ,
  77. /// <summary> 表示 try/catch/finally/fault 块。
  78. /// </summary>
  79. TryExpression = ,
  80. /// <summary> 表示表达式和类型之间的操作。
  81. /// </summary>
  82. TypeBinaryExpression = ,
  83. /// <summary> 表示包含一元运算符的表达式。
  84. /// </summary>
  85. UnaryExpression = ,
  86. }

ExpressionTypeCode

  1. /// <summary> 解析器静态对象
  2. /// </summary>
  3. public static class Parser
  4. {
  5. private static readonly IExpressionParser[] Parsers = InitParsers();
  6.  
  7. static IExpressionParser[] InitParsers()
  8. {
  9. var codes = Enum.GetValues(typeof(ExpressionTypeCode));
  10. var parsers = new IExpressionParser[codes.Length];
  11.  
  12. foreach (ExpressionTypeCode code in codes)
  13. {
  14. if (code.ToString().EndsWith("Expression"))
  15. {
  16. var type = Type.GetType(typeof(Parser).Namespace + "." + code.ToString() + "Parser");
  17. if (type != null)
  18. {
  19. parsers[(int)code] = (IExpressionParser)Activator.CreateInstance(type);
  20. }
  21. }
  22. }
  23. return parsers;
  24. }
  25.  
  26. /// <summary> 得到表达式类型的枚举对象 </summary>
  27. /// <param name="expr"> 扩展对象:Expression </param>
  28. /// <returns> </returns>
  29. public static ExpressionTypeCode GetCodeType(Expression expr)
  30. {
  31. if (expr == null)
  32. {
  33. return ExpressionTypeCode.Null;
  34. }
  35. if (expr is BinaryExpression)
  36. {
  37. return ExpressionTypeCode.BinaryExpression;
  38. }
  39. if (expr is BlockExpression)
  40. {
  41. return ExpressionTypeCode.BlockExpression;
  42. }
  43. if (expr is ConditionalExpression)
  44. {
  45. return ExpressionTypeCode.ConditionalExpression;
  46. }
  47. if (expr is ConstantExpression)
  48. {
  49. return ExpressionTypeCode.ConstantExpression;
  50. }
  51. if (expr is DebugInfoExpression)
  52. {
  53. return ExpressionTypeCode.DebugInfoExpression;
  54. }
  55. if (expr is DefaultExpression)
  56. {
  57. return ExpressionTypeCode.DefaultExpression;
  58. }
  59. if (expr is DynamicExpression)
  60. {
  61. return ExpressionTypeCode.DynamicExpression;
  62. }
  63. if (expr is GotoExpression)
  64. {
  65. return ExpressionTypeCode.GotoExpression;
  66. }
  67. if (expr is IndexExpression)
  68. {
  69. return ExpressionTypeCode.IndexExpression;
  70. }
  71. if (expr is InvocationExpression)
  72. {
  73. return ExpressionTypeCode.InvocationExpression;
  74. }
  75. if (expr is LabelExpression)
  76. {
  77. return ExpressionTypeCode.LabelExpression;
  78. }
  79. if (expr is LambdaExpression)
  80. {
  81. return ExpressionTypeCode.LambdaExpression;
  82. }
  83. if (expr is ListInitExpression)
  84. {
  85. return ExpressionTypeCode.ListInitExpression;
  86. }
  87. if (expr is LoopExpression)
  88. {
  89. return ExpressionTypeCode.LoopExpression;
  90. }
  91. if (expr is MemberExpression)
  92. {
  93. return ExpressionTypeCode.MemberExpression;
  94. }
  95. if (expr is MemberInitExpression)
  96. {
  97. return ExpressionTypeCode.MemberInitExpression;
  98. }
  99. if (expr is MethodCallExpression)
  100. {
  101. return ExpressionTypeCode.MethodCallExpression;
  102. }
  103. if (expr is NewArrayExpression)
  104. {
  105. return ExpressionTypeCode.NewArrayExpression;
  106. }
  107. if (expr is NewExpression)
  108. {
  109. return ExpressionTypeCode.NewArrayExpression;
  110. }
  111. if (expr is ParameterExpression)
  112. {
  113. return ExpressionTypeCode.ParameterExpression;
  114. }
  115. if (expr is RuntimeVariablesExpression)
  116. {
  117. return ExpressionTypeCode.RuntimeVariablesExpression;
  118. }
  119. if (expr is SwitchExpression)
  120. {
  121. return ExpressionTypeCode.SwitchExpression;
  122. }
  123. if (expr is TryExpression)
  124. {
  125. return ExpressionTypeCode.TryExpression;
  126. }
  127. if (expr is TypeBinaryExpression)
  128. {
  129. return ExpressionTypeCode.TypeBinaryExpression;
  130. }
  131. if (expr is UnaryExpression)
  132. {
  133. return ExpressionTypeCode.UnaryExpression;
  134. }
  135. return ExpressionTypeCode.Unknown;
  136. }
  137.  
  138. /// <summary> 得到当前表达式对象的解析组件 </summary>
  139. /// <param name="expr"> 扩展对象:Expression </param>
  140. /// <returns> </returns>
  141. public static IExpressionParser GetParser(Expression expr)
  142. {
  143. var codetype = GetCodeType(expr);
  144. var parser = Parsers[(int)codetype];
  145. if (parser == null)
  146. {
  147. switch (codetype)
  148. {
  149. case ExpressionTypeCode.Unknown:
  150. throw new ArgumentException("未知的表达式类型", "expr");
  151. case ExpressionTypeCode.Null:
  152. throw new ArgumentNullException("expr", "表达式为空");
  153. default:
  154. throw new NotImplementedException("尚未实现" + codetype + "的解析");
  155. }
  156. }
  157. return parser;
  158. }
  159.  
  160. public static void Select(Expression expr, ParserArgs args)
  161. {
  162. GetParser(expr).Select(expr, args);
  163. }
  164.  
  165. public static void Where(Expression expr, ParserArgs args)
  166. {
  167. GetParser(expr).Where(expr, args);
  168. }
  169.  
  170. public static void GroupBy(Expression expr, ParserArgs args)
  171. {
  172. GetParser(expr).GroupBy(expr, args);
  173. }
  174.  
  175. public static void Having(Expression expr, ParserArgs args)
  176. {
  177. GetParser(expr).Having(expr, args);
  178. }
  179.  
  180. public static void OrderBy(Expression expr, ParserArgs args)
  181. {
  182. GetParser(expr).OrderBy(expr, args);
  183. }
  184.  
  185. public static void Object(Expression expr, ParserArgs args)
  186. {
  187. GetParser(expr).Object(expr, args);
  188. }
  189.  
  190. }

Parser

原理分解

首先将所有类型的表达式树以枚举的形式表现出来,1来是为了更直观便于2是为了给他们编号

有了编号就可以方便的在数组或集合中给他们安排位置

初始化

在Parser类中,放置一个静态字段

  1. private static readonly IExpressionParser[] Parsers = InitParsers();

在InitParsers方法中,使用反射查找当前命名空间下名称为 枚举名 + Parser 的类,如果有则实例化,并根据枚举的值,在集合中保存

ps:枚举名 + Parser 作为解析器的命名规则,仅仅是为了方便反射调用,Parsers[0] = new xxx() 这个依然是可以由后期调用绑定的

调用

然后提供一个方法,用于获取当前表达式对象对应的枚举值

  1. public static ExpressionTypeCode GetCodeType(Expression expr)
  2. {
  3. if (expr == null)
  4. {
  5. return ExpressionTypeCode.Null;
  6. }
  7. if (expr is BinaryExpression)
  8. {
  9. return ExpressionTypeCode.BinaryExpression;
  10. }
  11. if (expr is BlockExpression)
  12. {
  13. return ExpressionTypeCode.BlockExpression;
  14. }
  15. ...
  16. ...
  17. return ExpressionTypeCode.Unknown;
  18. }

这里的方法我没有选择用反射来获取枚举值,还是基于对性能的考虑,这样测试快5~10倍,有兴趣的可以测试一下

  1. public static ExpressionTypeCode GetCodeType(Expression expr)
  2. {
  3. if (expr == null)
  4. {
  5. return ExpressionTypeCode.Null;
  6. }
  7. ExpressionTypeCode tc;
  8. if (Enum.TryParse(expr.GetType().Name, out tc))
  9. {
  10. return tc;
  11. }
  12. return ExpressionTypeCode.Unknown;
  13. }

反射代码

得到枚举之后,就可以按枚举的值,从集合中获取已经实例化的解析器为了方便调用,写了一个方法GetParser

  1. public static IExpressionParser GetParser(Expression expr)
  2. {
  3. var codetype = GetCodeType(expr);
  4. var parser = Parsers[(int)codetype];
  5. if (parser == null)
  6. {
  7. switch (codetype)
  8. {
  9. case ExpressionTypeCode.Unknown:
  10. throw new ArgumentException("未知的表达式类型", "expr");
  11. case ExpressionTypeCode.Null:
  12. throw new ArgumentNullException("expr", "表达式为空");
  13. default:
  14. throw new NotImplementedException("尚未实现" + codetype + "的解析");
  15. }
  16. }
  17. return parser;
  18. }

得到解析器之后,就可以做爱做的事了,

好了我也有点累了,先这样吧

未完待续...

  干货!表达式树解析"框架"(2)

  干货!表达式树解析"框架"(3)

干货!表达式树解析"框架"(1)的更多相关文章

  1. 干货!表达式树解析"框架"(2)

    最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html 为了过个好年,我还是赶快把这篇完成了吧 声明 本文内容需要有一定 ...

  2. 干货!表达式树解析"框架"(3)

    最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html 这应该是年前最后一篇了,接下来的时间就要陪陪老婆孩子了 关于表达 ...

  3. 轻量级表达式树解析框架Faller

    有话说 之前我写了3篇关于表达式树解析的文章 干货!表达式树解析"框架"(1) 干货!表达式树解析"框架"(2) 干货!表达式树解析"框架" ...

  4. 表达式树解析"框架"

    干货!表达式树解析"框架"(2)   为了过个好年,我还是赶快把这篇完成了吧 声明 本文内容需要有一定基础的开发人员才可轻松阅读,如果有难以理解的地方可以跟帖询问,但我也不一定能回 ...

  5. Lambda表达式树解析(下)

    概述 前面章节,总结了Lambda树的构建,那么怎么解析Lambda表达式树那?Lambda表达式是一种委托构造而成,如果能够清晰的解析Lambda表达式树,那么就能够理解Lambda表达式要传递的正 ...

  6. Lambda表达式树解析(下)包含自定义的provider和查询

    概述 前面章节,总结了Lambda树的构建,那么怎么解析Lambda表达式树那?Lambda表达式是一种委托构造而成,如果能够清晰的解析Lambda表达式树,那么就能够理解Lambda表达式要传递的正 ...

  7. 介绍一个可以将Expression表达式树解析成Transact-SQL的项目Expression2Sql

    一.Expression2Sql介绍 Expression2Sql是一个可以将Expression表达式树解析成Transact-SQL的项目.简单易用,几分钟即可上手使用,因为博主在设计Expres ...

  8. C#3.0新增功能10 表达式树 03 支持表达式树的框架类型

    连载目录    [已更新最新开发文章,点击查看详细] 存在可与表达式树配合使用的 .NET Core framework 中的类的大型列表. 可以在 System.Linq.Expressions 查 ...

  9. 借助表达式树感受不一样的CRUD

    借助表达式树感受不一样的CRUD Intro 最近有个想法,想不写 sql 语句,做一个类似于 ORM 的东西,自己解析表达式树,生成要执行的 sql 语句,最后再执行 sql 语句,返回相应结果. ...

随机推荐

  1. 使用Javascript快速获取URL参数

    首先:原文在这   Quick Tip: Get URL Parameters with JavaScript function getAllUrlParams(url) { var queryStr ...

  2. Android资源站

    用这个帖子记录下看到的好的android资源站 1.各种资源:http://appxcode.com/ 2.图标 2.1 http://www.easyicon.net 2.2 http://www. ...

  3. NOIp 2016 总结

    NOIp 2016 总结 -----YJSheep Day 0 对于考前的前一天,晚自习在复习图论的最短路和生成树,加深了图的理解.睡得比较早,养足精力明日再战. Day 1 拿到题目,先过一边,题目 ...

  4. iOS SQLite3的使用

    1.创建可修改的数据库文件 //应用包内的内容是不可写的,所以需要把应用包内的数据库拷贝一个副本到资源路径去 - (void)createEditableDatabase{ BOOL success; ...

  5. 2.1 -1.0 Xcode(发布时间、使用、快捷键、插件相关)

    本文并非最终版本,如有更新或更正会第一时间置顶,联系方式详见文末 如果觉得本文内容过长,请前往本人 “简书” 1.0 Xcode 发布时间 版本 iOS 版本 手机 日期 特殊介绍 Xcode 3.1 ...

  6. iOS 与 惯性滚动

    注:以下所有例子均 只 在 iOS 的微信中测试过,但对于饿了么APP的内置浏览器同样适用(两者使用相同内核) 引题 工作中常常有需要显示大量信息的情况,列表超出一屏就涉及到滚动的问题.例如 - va ...

  7. touches 事件捕获不到

    在UIView上加载了一个UIScrollView(全屏),touches 事件捕获不到了 原因:UIView的touch事件被UIScrollView捕获了,无法传递下去 解决方法:写一个UIScr ...

  8. winform控件在Enable=false的情况下改变它的字体颜色

    [System.Runtime.InteropServices.DllImport("user32.dll ")]         public static extern int ...

  9. hadoop---前期准备---屌丝

    hadoop要求有多台机子进行后续的数据处理,作为屌丝一枚,怎么才能搭建一个合适的环境学习hadoop?这就是本篇将要介绍的----前期准备. 搭建环境没啥好说的,说一下搭建环境多需要的吧 硬件:电脑 ...

  10. SubVersion Ubuntu

    UbuntuサーバにSubversionを入れる Linux, 開発ツール |    Ubuntuサーバが無事に動いたので.続いてSubversionを入れてみる. こんな感じの環境を考える. Apa ...