打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
货!表达式树解析"框架"(1)

关于我和表达式树

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

Lamda + 表达式树的性能瓶颈

  对于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对象,或许应该把他称之为解决方案或是别的

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

你应该了解的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        解析器参数,在解析表达式树的方法中保持传递,可以保存解析中所使用的参数和保存解析结果

代码

    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;}



本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
干货!表达式树解析"框架"(3)
C# 常见操作符整理
Simple tree-based interpeter - ANTLR 3 wiki
xpath.js
使用 Antlr 开发领域语言
Lemon语法分析生成器
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服