前面我们对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 表达式可以用在任何需要使用匿名方法,或是代理的地方。我们看看下面的代码:
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下看到的代码:
2 return (i % 2) == 0;
3 });
4 List<int> evenNumbers1 = numbers.FindAll(delegate (int i) {
5 return (i % 2) == 0;
6 });
现在看看他们的IL:
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表达式的标准写法为:
被编译器编译为:
其中=>为Lambda的操作符。
比如前面的代码:List<int> evenNumbers = numbers.FindAll( i => ( i % 2 ) == 0 );我们可以理解为:List<int> evenNumbers = numbers.FindAll( (i) => (( i % 2 ) == 0 ));我们也可以现实的指示输入参数的类型。当有有多行处理表达式时,需要使用大括号包起来,例如:
当输入参数有多个时:
当没有参数的时候:()里面可以为空。
局部变量也可以在Lambda表达式中使用,例如
最后希望大家对CLR系列和LINQ系列提出宝贵的建议以及希望增加对什么知识点的讲解。谢谢!
待续。。。