.NET Lambda表达式的“语义”
Lambda表达式的增强在于“语义”二字。“语义”是指代码所表现出来的含义,说的更通俗一些,便是指一段代码给阅读者的“感觉”如何。为了说明这个例子,我们还是使用示例来说明问题。
这个例子是这样的:“请写一个方法,输入一个表示整型的字符串列表,并返回一个列表,包含其中偶数的平方,并且需要按照平方后的结果排序”。很简单,不是吗?相信您一定可以一蹴而就:
- static List< int> GetSquaresOfPositive(List< string> strList)
- {
- List< int> intList = new List< int>();
- foreach (var s in strList) intList.Add(Int32.Parse(s));
- List< int> evenList = new List< int>();
- foreach (int i in intList)
- {
- if (i % 2 == 0) evenList.Add(i);
- }
- List< int> squareList = new List< int>();
- foreach (int i in evenList) squareList.Add(i * i);
- squareList.Sort();
- return squareList;
- }
我想问一下,这段代码给您的感觉是什么?它给我的感觉是:做了很多事情。有哪些呢?
1. 新建一个整数列表intList,把参数strList中所有元素转化为整型保存起来。
2. 新建一个整数列表evenList,把intList中的偶数保存起来。
3. 新建一个整数列表squareList,把evenList中所有数字的平方保存起来。
4. 将squareList排序。
5. 返回squareList。
您可能会问:“当然如此,还能怎么样?”。事实上,如果使用了Lambda表达式,代码就简单多了:
.NET Lambda表达式的语义:写法范例
- static List< int> GetSquaresOfPositiveByLambda(List< string> strList)
- {
- return strList
- .Select(s => Int32.Parse(s)) // 转成整数
- .Where(i => i % 2 == 0) // 找出所有偶数
- .Select(i => i * i) // 算出每个数的平方
- .OrderBy(i => i) // 按照元素自身排序
- .ToList(); // 构造一个List
- }
配合.NET 3.5中定义的扩展方法,这段代码可谓“一气呵成”(在实际编码过程中,老赵更倾向于把这种简短的“递进式”代码写作一行)。那么这行代码的“语义”又有什么变化呢?在这里,“语义”的变化在于代码的关注点从“怎么做”变成了“做什么”。这就是Lambda表达式的优势。
在第一个方法中,我们构造了多个容器,然后做一些转化,过滤,并且向容器填充内容。其实这些都是“怎么做”,也就是所谓的“how (to do)”。但是这些代码并不能直接表示我们想要做的事情,我们想要做的事情其实是“得到XXX”,“筛选出YYY”,而不是“创建容器”,“添加元素”等操作。
在使用Lambda表达式的实现中,代码变得“声明式(declarative)”了许多。所谓“声明式”,便是“声称代码在做什么”,而不像“命令式(imperative)”的代码在“操作代码怎么做”。换句话说,“声明式”关注的是“做什么”,是指“what (to do)”。上面这段声明式的代码,其语义则变成了:
1. 把字符串转化为整数
2. 筛选出所有偶数
3. 把每个偶数平方一下
4. 按照平方结果自身排序
5. 生成一个列表
至于其中具体是怎么实现的,有没有构造新的容器,又是怎么向容器里添加元素的……这些细节,使用Lambda表达式的代码一概不会关心——这又不是我们想要做的事情,为什么要关心它呢?
虽然扩展方法功不可没,但我认为,Lambda表达式在这里的重要程度尤胜前者,因为它负责了最关键的“语义”。试想,“i => i * i”给您的感觉是什么呢?是构造了一个委托吗(当然,您一定知道在这里其实构造了一个匿名方法)?至少对我来说,它的含义是“把i变成i * i”;同样,“i => i % 2 == 0”给我的感觉是“(筛选标准为)i模2等于零”,而不是“构造一个委托,XXX时返回true,否则返回false”;更有趣的是,OrderBy(i => i)给我的感觉是“把i按照i自身排序”,而不是“一个返回i自身的委托”。这一切,都是在“声明”这段代码在“做什么”,而不是“怎么做”。
没错,“类型推演”,“省略括号”和“省略return关键字”可能的确都是些“细斜的功能,但也正是这些细微之处带来了编码方式上的关键性改变。
以上就通过一个字符串列表的范例,介绍了.NET Lambda表达式的语义特征。
【编辑推荐】