• Expression Tree不完全入门


     在.NET Framework 3.5中提供了表达式目录树(Expression Tree),它是一种抽象语法树或者说它是一种数据结构。在了解他之前我们需要从委托说起,
    在.NET中委托是使用delegate 关键字声明的一个引用类型,类似于 C++ 中的函数指针,你可以把委托理解为方法的别名,只不过他代表了一类的方法。
    委托是类型安全和可靠的。

    1.我们举一个例子来简单说明委托的使用,假设我们有一个人员组织库,我们要列出库中所有人员的名字,下面是代码:

    public class Employe
        {
            public string Name { get; set; }
            public int Age { get; set; }
    
            public Employe(string name,int age)
            {
                this.Name = name;
                this.Age = age;
            }
        }
    public delegate void ProcessEmployeDelegate(Employe emp);
        
    public class EmpDataBase
    {
            List<Employe> list = new List<Employe> 
            {
                new Employe("Cary",25),
                new Employe("James",34)
            };
            
            public void ProcessEmploye(ProcessEmployeDelegate processEmploye)
            {
                foreach (Employe emp in list)
                {
                    processEmploye(emp);
                }
            }
    }

    class Program
    {        
            static void ShowEmpName(Employe emp)
            {            
                "名字:{0}".FormatWriteLine(emp.Name);
            }
         
            static void Main()
            {            
                EmpDataBase empdb = new EmpDataBase();
                empdb.ProcessEmploye(ShowEmpName);
    }

    }

    下面是结果:

    名字:Cary
    名字:James

    上面我为String加了一个简单的扩展方法,代码如下:

    public static void FormatWriteLine(this string format, params object[] args)
    {
         Console.WriteLine(string.Format(format, args));
    }
    2.到.NET2.0时代,引入了匿名方法,使用匿名方法我们就不必创建单独的方法,而是将匿名方法直接作为参数传递。于是上面的主程序就可以改变为如下代码:
    class Program
    {        
           static void Main()
            {            
                EmpDataBase empdb = new EmpDataBase();
                empdb.ProcessEmploye(delegate(Employe emp)
                {
                    "名字:{0}".FormatWriteLine(emp.Name);
                });
    }
    }
    3.进入.NET3.X时代,我们又有了Lambda表达,可以将delegate关键字也去掉,让人彻底的看不见委托的影子,代码如下:
    class Program
    {        
            static void Main()
            {            
                EmpDataBase empdb = new EmpDataBase();
                empdb.ProcessEmploye(emp=>"名字:{0}".FormatWriteLine(emp.Name));
    }
    }
    4.到此为止我们的主程序是不是简化了许多。不过我们还声明了一个ProcessEmployeDelegate委托,我们可以使用Action<T>或Func来代替,Action<T>
    和Func<T,TResult>的功能没有什么区别,只是Action<T>没有返类型。代码如下:
    public void ProcessEmploye(Action<Employe> processEmploye)
    {
          foreach (Employe emp in list)
          {
               processEmploye(emp);
          }
    }

    5.了解了lambda表达式,其对应的具体语法树就是Expression Tree,其对应的相关API都在System.Linq.Expressions命名空间下,如下图:
    image

    我们来看下Expression类的结构,该类有四个属性:

      Body:获取表达式的主体;
      Parameters:获取Lambda表达示的参数;
      NodeType:得到树中某些节点的表达式类型(ExpressionType),这是一个有45种不同值的枚举类型,代表表达式节点的所有可能类型,如返回常数、
                             也可能返回参数、或者返回一个值是否小于另外一个(<),或者返回一个值是否大于另外一个(>),或者返回两个值的和( )等等。
      Type:得到表达式的静态类型,在本例中,表达式的类型是Func。

    6.我们构建,遍历,修改表达式目录树,还可以执行表达式目录树,下面继续举几个例子来说明。找出下面字符串数字中以“C”开头的员工(x => x.StartsWith("C")):

    String[] names = new string[2] { "Cary","James"};
    Expression<Func<String, Boolean>>  expression1 = (x) => x.StartsWith("C");
    "Expression is {0}\r\n".FormatWriteLine(expression1.ToString());          
    foreach (String name in  names.Where(expression1.Compile()))
    {        
        "{0 }".FormatWriteLine(name);
    }

    7.找出人员库中年龄为25的员工,表达式为:Expression is age => (age.Age = 25)

    ConstantExpression constEmpAge = Expression.Constant(25);
    ParameterExpression paramAge =Expression.Parameter(typeof(Employe), "age");
    MemberExpression mex =LambdaExpression.PropertyOrField(paramAge, "Age");
    
    BinaryExpression filter = Expression.Equal(mex, constEmpAge);
    Expression<Func<Employe, bool>> expression2 = Expression.Lambda<Func<Employe, bool>>
      (filter,new ParameterExpression[] { paramAge });            
    "Expression is {0}\r\n".FormatWriteLine(expression2.ToString());
    foreach (Employe emp in list.Where(expression2.Compile()))
    {
          "{0}:{1}".FormatWriteLine(emp.Name,emp.Age);
    }

    8.我们还可以使用Expression Tree Visualizer来查看表达式目录树的相关信息,如下图:

    image

    Expression Tree Visualizer的使用将ExpressionTreeVisualizer中的.dll文件拷贝到..\Program Files\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\Visualizers.中。

    本文没有过多深入的内容,只是希望给大家带来一些对Expression的基本认识,希望本文能对您有用。

  • 相关阅读:
    用TortoiseSVN忽略文件或文件夹(ignore)(网络摘抄记录)
    GridView解决同一行item的高度不一样,如何同一行统一高度问题?
    解决android studio引用远程仓库下载慢(转)
    Databinding在自定义ViewGroup中如何绑定view
    (转 )【Android那些高逼格的写法】InvocationHandler与代理模式
    (转)秒懂,Java 注解 (Annotation)你可以这样学
    View拖拽 自定义绑定view拖拽的工具类
    bcrypt对密码加密的一些认识(学习笔记)
    Node.js+Koa开发微信公众号个人笔记(三)响应文本
    Node.js+Koa开发微信公众号个人笔记(二)响应事件
  • 原文地址:https://www.cnblogs.com/carysun/p/ExpressionTree.html
Copyright © 2020-2023  润新知