• Linq系列:基础与本质(Part III)


    -

    前面我们对LINQ的本质,以及MS针对LINQ对3.5新增的几个类做了分析。作为本系列的第一篇:基础与本质的最后一篇,我想对Lambda表达式讲解一下。本来Lambda表达式也可以放到系列c#3.x学习中,我想还是放到LINQ系列比较好讲一些。

    1 Lambda表达式例子

    先来熟悉一下Lambda的一般样子,代码:

     1 x => x * 2;
     2 (x, y) => x * 10 + y;
     3 (x, y, z) => (1 / x + 10) * y + z;
     4 Func<int, int> f1;
     5 f1 = x => x * 2
     6 Func<int, int, int> f2;
     7 f2 = (x, y) => x * 10 + y; 
     8 Func<int, int, int, int> f3;
     9 f3 = (x, y, z) => (1 / x + 10) * y + z;
    10 // A lambda expression with no arguments
    11 Func<int> f4 = ()=> 10;
    12 int r1 = f1(10);
    13 int r2 = f2(5, 10);

    这些是C#3.0新特性为Lambda定义的格式。

    Func<int, int> f1 = x => x * 2;<=> Func<int, int> f1 = delegate(int x){return x * 2;};

    我们说这两种方式可以说在某种情况下是等价的,为什么等价的呢?请看本文的第二部分的分析

    2 Lambda 表达本质

    Lambda 表达式可以用在任何需要使用匿名方法,或是代理的地方。我们看看下面的代码:

    1 List<int> numbers = new List<int>102028401358 };
    2 List<int> evenNumbers = numbers.FindAll( i => ( i % 2 ) == 0 );
    3 List<int> evenNumbers1 = numbers.FindAll( delegate(  int i )
    4 {
    5   return ( i % 2 ) == 0;
    6  } );

    我们通过Reflector工具可以看到编译器会将Lambda表达式编译为标准的匿名方法。下面是在Reflector下看到的代码:

    1  List<int> evenNumbers = numbers.FindAll(delegate (int i) {
    2          return (i % 2== 0;
    3      });
    4  List<int> evenNumbers1 = numbers.FindAll(delegate (int i) {
    5          return (i % 2== 0;
    6      });

    现在看看他们的IL:

     1 L_0060: ldftn bool LINQProject.test2::<TestLambda>b__1(int32)
     2 L_0066: newobj instance void [mscorlib]System.Predicate`1<int32>::.ctor(object, native int)
     3 L_006b: stsfld class [mscorlib]System.Predicate`1<int32> LINQProject.test2::CS$<>9__CachedAnonymousMethodDelegate3
     4 L_0070: br.s L_0072
     5 L_0072: ldsfld class [mscorlib]System.Predicate`1<int32> LINQProject.test2::CS$<>9__CachedAnonymousMethodDelegate3
     6 L_0077: callvirt instance class [mscorlib]System.Collections.Generic.List`1<!0> [mscorlib]System.Collections.Generic.List`1<int32>::FindAll(class [mscorlib]System.Predicate`1<!0>)
     7 L_007c: stloc.1 
     8 L_007d: ldloc.0 
     9 L_007e: ldsfld class [mscorlib]System.Predicate`1<int32> LINQProject.test2::CS$<>9__CachedAnonymousMethodDelegate4
    10 L_0083: brtrue.s L_0098
    11 L_0085: ldnull 
    12 L_0086: ldftn bool LINQProject.test2::<TestLambda>b__2(int32)
    13 L_008c: newobj instance void [mscorlib]System.Predicate`1<int32>::.ctor(object, native int)
    14 L_0091: stsfld class [mscorlib]System.Predicate`1<int32> LINQProject.test2::CS$<>9__CachedAnonymousMethodDelegate4
    15 L_0096: br.s L_0098
    16 L_0098: ldsfld class [mscorlib]System.Predicate`1<int32> LINQProject.test2::CS$<>9__CachedAnonymousMethodDelegate4
    17 L_009d: callvirt instance class [mscorlib]System.Collections.Generic.List`1<!0> [mscorlib]System.Collections.Generic.List`1<int32>::FindAll(class [mscorlib]System.Predicate`1<!0>)
    18 L_00a2: stloc.2

    通过对Lambda表达式的IL的分析是编译器自动生成相应的静态成员和静态方法,带来着一些的都是编译器,CLR并没有做出实质的改变,这就更加验证了上一篇文章的说明,委托,匿名方法,Lambda表达式都是一脉相承的,实现原理都是通过委托。

    3 Lambda表达式的分析

    MS定义Lambda表达式的标准写法为:

    ArgumentsToProcess => StatementsToProcess

    被编译器编译为:

    inputs (delegate parameters) =>Expression to be evaluated(expression return must match delegate return value type)

    其中=>为Lambda的操作符。

    比如前面的代码:List<int> evenNumbers = numbers.FindAll( i => ( i % 2 ) == 0 );我们可以理解为:List<int> evenNumbers = numbers.FindAll( (i) => (( i % 2 ) == 0 ));我们也可以现实的指示输入参数的类型。当有有多行处理表达式时,需要使用大括号包起来,例如:

    Code

    当输入参数有多个时:

    Code

    当没有参数的时候:()里面可以为空。

    局部变量也可以在Lambda表达式中使用,例如

    Code

    最后希望大家对CLR系列和LINQ系列提出宝贵的建议以及希望增加对什么知识点的讲解。谢谢!

    待续。。。

    版权所有归"布衣软件工作者".未经容许不得转载.
  • 相关阅读:
    转载:javaweb学习总结(八)——HttpServletResponse对象(二)
    转载:javaweb学习总结(七)——HttpServletResponse对象(一)
    转载:javaweb学习总结(六)——Servlet开发(二)
    转载:javaweb学习总结(五)——Servlet开发(一)
    转载:javaweb学习总结(四)——Http协议
    蓝桥杯 答题分数
    Saruman's Army (POJ 3069)
    Best Cow Line (POJ 3217)
    区间调度问题
    硬币问题
  • 原文地址:https://www.cnblogs.com/gjcn/p/1336047.html
Copyright © 2020-2023  润新知