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


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

     

    关于我和表达式树

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

    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" };
        }
    ParserArgs
    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);
            }
        }
    ExpressionParser
        /// <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,
        }
    ExpressionTypeCode
        /// <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);
            }
    
        }
    Parser

    原理分解

    首先将所有类型的表达式树以枚举的形式表现出来,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)

  • 相关阅读:
    11.3 校内模拟赛
    11.2 模拟赛题解报告
    11.1 校内模拟赛题解报告
    CF710E Generate a String
    CF165E Compatible Numbers
    CF1092F Tree with Maximum Cost
    2021,10,29 模拟赛题解报告
    LCT学习笔记
    FFT 快速傅里叶变换学习笔记
    拉格朗日插值学习笔记
  • 原文地址:https://www.cnblogs.com/blqw/p/3522677.html
Copyright © 2020-2023  润新知