zoukankan      html  css  js  c++  java
  • 【C#基础】拥抱Lambda(1):Lambda与表达式树

      写在开头,好奇从这里开始(当时让加查询条件,结果竟然是一句话来发挥神奇作用):

    this.TestGrade = CriteriaHelper.NewObject<ITestCase, DtoTestCase>("测试等级", a => a.Grade);

    1. 语法糖 Lambda

      在我看来,=>总是一个无敌可爱的符号。嗯,包括C语言里面的 -> 这个,它总像是在说“我指到这边,你看..”。

      找到了一张图[1],可以很好地说明lambda表达式,语法糖上的变化。

    // 匿名方法,方法如何写应该是深入骨髓的哦:
    
              delegate(string text) { return text.Length; }
    
    // Lambda表达式,作用与上行相同:
    
              (string text) => { return text.Length; }
    
    // 还可以省略括号,这看起来就更像goes to“看到这里”的感觉了:
    
              (string text) => text.Length
    
    // 让编译器推断参数类型:
    
              (text) => text.Length
    
    // 还可以省略括号:
    
              text => text.Length

      注:Lambda表达式在去掉花括号时(即仅有一句时),其实是不带;符号的,一般加上的;是赋值语句规则的。

      下面有一个例子,一个让人觉得“怎么会有传方法这种这么神奇操作”的例子:

        class Film
        {
            public string Name { get; set; }
            public int Year { get; set; }
        }
    
        // Main函数:
        var films = new List<Film>
        {
            new Film { Name = "Jaws", Year = 1975},
            new Film { Name = "Singing in the Rain", Year = 1952},
            new Film { Name = "Some like it Hot", Year = 1959},
            new Film { Name = "The Wizard of Oz", Year = 1939},
            new Film { Name = "American Beauty", Year = 1999}
        };
    
        Action<Film> print = film => Console.WriteLine("Name = {0}, Year = {1}", film.Name, film.Year);
        films.ForEach(print);
        // Console.WriteLine("
    ");
    
        films.FindAll(film => film.Year < 1955).ForEach(print);
        // Console.WriteLine("
    ");
     
        films.Sort((f1,f2) => f1.Name.CompareTo(f2.Name));
        films.ForEach(print);

    2. Lambda表达式与表达式树(Expression tree)

      在开启本节内容前,先捋清一下:

    图2 [2]

      C#编译成公共中间语言(CIL或者IL,成果就是组件.dll文件),程序运行时再由实时编译器(Just in Time,JIT)转化为特定于CPU的语言。

    2.1 表达式树

      表达式树就是对象构成的树,树中每个节点本身都是一个表达式。Expression类主要包括两个属性:

                Type属性:表达式求值后的返回类型。

                NodeType属性:返回所代表的表达式的种类,也是节点类型。

      表达式树,有很多不同类型的节点。

      例如可以这样想象:一个数是一个节点,一个运算符也是一个节点,那么一个简单的2+3表达式,就是有3个节点的树形关系。

        Expression firstArg = Expression.Constant(2);
        Expression secondArg = Expression.Constant(3);
        Expression add = Expression.Add(firstArg, secondArg);
    
        Console.WriteLine(add); // 打印出来的是表达式 (2 + 3)

      注意:“叶”表达式总是最先创建的。

      注意:Expression.Constant或者是Expression.Add类型都是继承于Expression的,这棵树的所有节点,都是Expression类型。

     

    add

    BinaryExpression

    NodeType = Add

    Type = System.Int32

    firstArg

    ConstantExpression

    NodeType = Constant

    Type = System.Int32

    secondArg

    ConstantExpression

    NodeType = Constant

    Type = System.Int32

    图3 上例代码表达式树树形化表示

      继续上面的例子,既然打印出来的仅是表达式(2 + 3) ,那么能不能打印运行结果呢?

      可以想象一下,节点里面不管是数值或是运算符,其实对于表达式树来说,也就是多个节点或者少个节点的事。如果把节点当成没有实际意义的“圣诞树挂饰”(因为树上的节点“不干活”),那表达式树到底有什么意义?

      那句话是这样的,“没有Lambda表达式,表达式树几乎没有任何价值”。

      我算是有些明白,“code as data”是什么意思。没有数据,代码是惘然的。但是“叶子”有了,怎么让树“活过来”?微软提供的方式是:将表达式树编译成委托——既然有各种类型的节点,怎么不能有方法类型的节点呢。

        Expression leftArg = Expression.Constant(2);
        Expression rightArg = Expression.Constant(3);
        Expression add = Expression.Add(leftArg, rightArg);
    
        Func<int> compiled = Expression.Lambda<Func<int>>(add).Compile();
        Console.WriteLine(compiled());

     

     

      C#当中Lambda表达式支持表达式树,不过还需要该节点使用Compile()方法(大概就是编译成对应的Func<T>类型,此方法涉及到System.Reflection.MethodInfo,这节内容放到后面来谈)。

       Expression<Func<int>> return5 = () => 5;   // () => 5是一个Lambda表达式
    
       Func<int> compiled = return5.Compile();    // 把Lambda表达式转换成表达式树。
                                // (这种转换有限制,此处不详谈。)

    2.2 Lambda表达式与LINQ

      LINQ(Language Integrated Query)是一种基于中间查询能够直接反馈到C#语言环境当中的技术。

      LINQ提供器的中心思想在于:从一个熟悉的源语言(比如C#)生成一个表达式树,将结果作为一个中间格式,再将其转换成目标平台上的本地语言(比如SQL)。

      LINQ to Objects方式是:使用含有Lambda表达式的C#查询代码,再由转化为相应的IL,在CLR中执行。

      LINQ to SQL方式:编译成使用表达式树IL,在执行时,动态执行sql语句(IL已经处理好怎么让LINQ to SQL提供器处理到本地语言)。

       ……

      除了LINQ to Objects和LINQ to SQL还有其他的数据查询方式,此处不展开。

     ==================================================================================

      下节内容:

      【C#基础】拥抱Lambda(1):表达式树与LINQ

    注释:

    [1]  Lambda语法简写

    [2] 图源自 维基百科

    [3] 此笔记主要参考 《深入理解C#》(第3版)Jon Skeet 著  姚琪琳 译

  • 相关阅读:
    数据可视化之DAX篇(二十)Think in DAX 之报表自动化实践
    数据可视化之DAX篇(十九)值得你深入了解的函数:SUMMARIZE
    数据可视化之DAX篇(十八)收藏 | DAX代码格式指南
    数据可视化之DAX篇(十七)Power BI表格总计行错误的终极解决方案
    atomic_compare_exchange_weak_explicit (Atomic operations) – C 中文开发手册
    Spring Boot的How-to指南:嵌入式Web服务器
    C# 文本文件的读写
    CSS outline 属性
    operator (Numeric & Mathematical) – Python 中文开发手册
    HTML DOM Style animationDirection 属性
  • 原文地址:https://www.cnblogs.com/carmen-019/p/10534291.html
Copyright © 2011-2022 走看看