zoukankan      html  css  js  c++  java
  • 16.C#初见Lambda表达式及表达式树(九章9.1-9.3)

      在说明Lambda相关知识前,我们需要了解Lambda表达式常用于LINQ,那么我们来聊下LINQ。

      LINQ的基本功能就是创建操作管道,以及这些操作需要的任何状态。这些操作表示了各种关于数据的逻辑:如何过滤、如何排序以及如何将不同的数据源连接在一起,等等。执行委托只是LINQ的众多能力之一。为了富有效率地使用数据库和其他查询引擎,我们需要以一种不同的方式来表示管道中的各个操作。这种不同的方式就可以使用Lambda表达式来表现。下面分别使用委托(使用匿名函数)和Lambda表达式来作出同样的事情:返回一个人的到现在一共活了多少天。

     1 class Person
     2 {
     3     public DateTime BirthDay { get; set; }
     4 }
     5 
     6 public delegate int GetLifeDays(Person p);//声明一个委托类型
     7 static void Main(string[] args)
     8 {
     9     Person p = new Person() { BirthDay = new DateTime(1900, 12, 17) };
    10 
    11     GetLifeDays gfd = delegate (Person x) { //实例化一个委托
    12 return (DateTime.Now - x.BirthDay).Days; 13 }; 14 Console.WriteLine(gfd(p)); 15 16 GetLifeDays gfd1 = (Person x) => { return (DateTime.Now - x.BirthDay).Days; }; 17 Console.WriteLine(gfd1(p)); 18 19 GetLifeDays gfd2 = (Person x) => (DateTime.Now - x.BirthDay).Days; //去除了后面的大括号,“;”为表达式结束,不是Lambda的结束 20 Console.WriteLine(gfd2(p)); 21 22 GetLifeDays gfd3 = (x) => { return (DateTime.Now - x.BirthDay).Days; }; //让编译器推断参数的类型 23 Console.WriteLine(gfd3(p)); 24 25 GetLifeDays gfd4 = (x) => (DateTime.Now - x.BirthDay).Days; //同时省去参数类型和大括号 26 Console.WriteLine(gfd4(p)); 27 28 GetLifeDays gfd5 = x => (DateTime.Now - x.BirthDay).Days; //再进一步,省去参数列表的括号 29 Console.WriteLine(gfd5(p)); 30 31 Console.ReadKey(); 32 }

       上述是单一参数的各种情况,对于有两个或多个参数的,效果是"一个到到从出生到某一天的相隔天数",某一天肯定是要大于出生那天啦。

     1 public delegate int GetDaysTo(Person p, DateTime d);
     2 static void Main(string[] args)
     3 {
     4     Person p = new Person() { BirthDay = new DateTime(1900, 12, 17) };
     5 
     6     DateTime d = new DateTime(2100, 12, 12);
     7     //使用匿名方法
     8     GetDaysTo gdt = delegate (Person x, DateTime y)
     9     {
    10         return (y - x.BirthDay).Days;
    11     };
    12     Console.WriteLine(gdt(p, d));
    13 
    14     GetDaysTo gdt1 = (Person x, DateTime y) => { return (y - x.BirthDay).Days; };
    15     Console.WriteLine(gdt1(p, d));
    16 
    17     GetDaysTo gdt2 = (Person x, DateTime y) => (y - x.BirthDay).Days;
    18     Console.WriteLine(gdt2(p, d));
    19 
    20     GetDaysTo gdt3 = (x, y) => (y - x.BirthDay).Days;
    21     Console.WriteLine(gdt3(p, d));
    22 
    23     //GetDaysTo gdt4 = x, y => (y - x.BirthDay).Days; Error
    24     //Console.WriteLine(gdt4(p, d));
    25 
    26     Console.ReadKey();
    27 }

      可以看出当参数为两个或两个以上时,不能省略参数列表中的括号,那也可以想像在语句两条或两条以上时,不能省略大括号

      下面结合之前的知识,对一个列表使用ambda表达式进行操作。

     1 //使用集合初始化器
     2 List<Person> l = new List<Person> {
     3     new Person { BirthDay=new DateTime(1990,11,11)},
     4     new Person { BirthDay=new DateTime(1890,12,12)},
     5     new Person { BirthDay=new DateTime(1891,12,12)},
     6     new Person { BirthDay=new DateTime(1892,12,12)},
     7     new Person() { BirthDay=new DateTime(1870,12,12)}
     8 };
     9 
    10 //找到大于new DateTime(1890,1,1)的人
    11 var result0 = l.FindAll(x => x.BirthDay > new DateTime(1890, 1, 1));
    12 
    13 //按年龄从小到大排序
    14 l.Sort((x, y) => x.BirthDay > y.BirthDay ? -1 : 1);
    15 foreach (var e in l)
    16 {
    17     Console.WriteLine((DateTime.Now - e.BirthDay).Days);
    18 }
    19 
    20 //循环打印每个人的出生天数,效果和上面的foreach一样
    21 l.ForEach(x => Console.WriteLine((DateTime.Now - x.BirthDay).Days));
    22 
    23 //找到BirthDay=new DateTime(1890,12,12)的人
    24 var result1 = l.Find(x => x.BirthDay == new DateTime(1890, 12, 12));

      接下来,我们来说下表达式树,.NET3.5的表达式提供了一种抽象的方式将一些代码表示成一个对象树,表达式树主要用于LINQ。System.Linq.Expressions命名空间包含了代表表达式的各个类,它们都继承于Expression,一个抽象的主要包含一些静态工厂方法的类,这些方法用于创建其它表达类的实例。

      Expression类包含两个属性:

    1. Type属性代表表达式求值后.NET类型,可把它视为一个返回类型。例如,一个表达式要获取一个字符串的长度,则该表达式的类型为int。
    2. NodeType属性返回所代表的表达式的种类。它是ExpressionType枚举的成员。
    1 Expression first = Expression.Constant(5);
    2 Expression result = Expression.Add(first, first);
    3 Console.WriteLine(result);

      断点对象各属性

      上图分别为first对象和result对象的各属性值。

    • 将表达式树编译成委托

      LambdaExpression是从Expression派生的类型之一。泛型类Expression<TDelegate>又是从LambdaExpression中派生。Expression和Expression<TDelegate>区别在于泛型类以静态类的方法标识了它是什么各类的表达式,也就是说,它确定了返回类型和参数。很显然,这是用TDelegate类型参数来表示的,它必须是一个委托类型。LambdaExpression有一个Compile方法能创建恰当类型的委托。Expression<TDelegate>也有一个同名的方法 ,但它静态类型化返回TDelegate类型的委托。如:

    1 Expression first = Expression.Constant(5);
    2 Expression result = Expression.Add(first, first);
    3 Func<int> add = Expression.Lambda<Func<int>>(result).Compile();
    4 Console.WriteLine(add()); //10
    • 将C#Lambda表达式转换为表达式树

      Lambda表达式能显式或隐式地转换为恰当的委托实例,然而这些并非唯一能进行的转换,还可以要求编译器通过你的Lambda表达式构建一个表达式树,在执行时创建Expression<TDelegate>的一个实例。如

    1 Expression<Func<int>> re = () => 5;
    2 Func<int> add0 = re.Compile();
    3 Console.WriteLine(add0());

       后面的那些内容真心太复杂了,自己实在理解不了,而且日常使用中也没有使用过,没有底气聊这个话题,想深入的朋友可以自己深入去了解,这里就做罢了吧。

      请斧正。

  • 相关阅读:
    修改SQL数据库中表字段类型时,报“一个或多个对象访问此列”错误的解决方法
    C# 正则表达式类 Match类和Group类
    JS流程控制语句 退出循环break 在while、for、do...while、while循环中使用break语句退出当前循环,直接执行后面的代码。
    JS流程控制语句 重复重复(for循环)语句结构: for(初始化变量;循环条件;循环迭代) { 循环语句 }
    JS流程控制语句 反反复复(while循环) 和for循环有相同功能的还有while循环, while循环重复执行一段代码,直到某个条件不再满足。
    JS流程控制语句 多重判断满足你各种需求 要在多组语句中选择一组来执行,使用if..else嵌套语句。
    JS流程控制语句 多种选择(Switch语句) 当有很多种选项的时候,switch比if else使用更方便。
    JS流程控制语句 做判断(if语句)if语句是基于条件成立才执行相应代码时使用的语句。语法:if(条件) { 条件成立时执行代码}
    JS流程控制语句 二选一 (if...else语句) 语法: if(条件) { 条件成立时执行的代码} else {条件不成立时执行的代码}
    JS数组 编程练习 使用Javascript语言,把以下数组 在页面显示如下图所示的图案
  • 原文地址:https://www.cnblogs.com/a2htray/p/4209604.html
Copyright © 2011-2022 走看看