重新回到那个用了很多次的语句:
- IEnumerable<int> numQuery = numbers.Where((number) => number % 2 == 0);
我们知道了Where是扩展方法,但是后面的(number) => number % 2 == 0又是什么?功能一看就明白了,就是选择是偶数的数字,但是深层机理又是什么样子的?
查一下MSDN,原来这种表达式也是3.0新增的东东,叫Lambda表达式。它的语法小凡就不再介绍,MSDN中有很详细的说明,再说也是狗尾续貂。但是,除了用Lambda表达式,像这样的函数还能传入什么形参?是不是只能用Lambda表达式了呢?
答案当然是不会的,如果真的是这样,那限制就太大了不是吗?再查一下MSDN吧(MSDN果然才是解决问题的王道口牙),我们看到Where是被重载了好几次的。
名称 | 说明 | |
---|---|---|
Where(Expression<(Of <(Func<(Of <(TElement, Boolean>)>)>)>)) | 基于谓词筛选值序列。 (由 Queryable 定义。) | |
Where(Expression<(Of <(Func<(Of <(TElement, Int32, Boolean>)>)>)>)) | 基于谓词筛选值序列。将在谓词函数的逻辑中使用每个元素的索引。 (由 Queryable 定义。) | |
Where(Func<(Of <(TElement, Boolean>)>)) | 基于谓词筛选值序列。 (由 Enumerable 定义。) | |
Where(Func<(Of <(TElement, Int32, Boolean>)>)) | 基于谓词筛选值序列。将在谓词函数的逻辑中使用每个元素的索引。 (由 Enumerable 定义。) |
其中有一个东西每个重载都会出现,就是Func<(Of <(TElement, Int32, Boolean>)>),好像是一个泛型,当然略有区别,有的是传入2个有的是传入3个类型。那Func<(Of <(TElement, Int32, Boolean>)>)又是什么?再深入一下,原来是一个委托!
- public delegate TResult Func<T1, T2, TResult>( T1 arg1, T2 arg2 )
委托是什么我想大家都用过,其实说穿了可以把它当成一个函数的指针(当然并不完全是,委托不等于函数指针,详细请见《.NET Framework 编程》一书)。
走到这一步,恐怕大家都明白了,其实就是一个函数,这个函数用bool类型作为返回值,也就是判断where条件是不是匹配。
针对上面那行代码,我们用纯委托的方式再重现一次。
首先定义一个方法,完成校验偶数的功能:
- private static bool IsEvenNumber(int number){ return number % 2 == 0;}
然后把一开始的那行代码替换成
- IEnumerable<int> numQuery = numbers.Where(new Func<int,bool>(IsEvenNumber));
OK,效果是完全一样的。这说明其实Lambda表达式其实在某种程度上就是一个匿名的函数,并且通过编译器来自动识别类型换成泛型的委托。小凡认为,Where的内部代码逻辑就是遍历每个numbers中的数字,并且调用传入的委托方法来进行校验。其实很简单不是吗?
虽然内部机理很简单,但是如果真的要用委托,可能代码量马上就增加了,相反用了Lambda表达式(当然事实上也需要编译器的支持),就能又简单又快捷的完成工作,为程序员考虑的语言才是好语言。
至此,从C# 3.0说以人为本就全部介绍完了,其中介绍了C# 3.0新增的LINQ和Lambda表达式,其它的一些新特性比如匿名类型等等就不描述了,谢谢大家。