.NET 3.0其实只是PF, CF, WF和CardSpace组合在一起的一个扩展库,.NET 2.0的核心部分没有什么变化,也不对应新的Visual Studio。.NET 3.5依旧没有动到.NET 2.0的核心,其新增的核心组件是LINQ,为了实现LINQ,必须要在语言层面上进行改进,于是C#进化到了3.0版。
C#3.0依赖的是Visual Studio 2008,或者说是.NET 3.5 SDK中的C# Compiler,很多C# 3.0的特性是由编译器完成的,C#3.0 + .NET2.0,也是非常有用的一个组合。从产品开发的角度来考虑,升级.NET Framework,是由一定的风险的,虽然从.NET 2.0到.NET 3.5,本质上只有扩充,但是从公司级别上来考虑,还是要谨慎对待。本文主要谈一下C#3.0中纯粹通过编译器实现的新功能,也就是说可以用Visual Studio 2008编译,并能运行于单纯的.NET 2.0环境下的那部分。本文只是杂谈,不涉及到如何使用这些功能,请参考MSDN或者其他文章。
1. lambda
lambda在其他语言里中出现过,应用比较多的就是python,而C++也通过boost库实现了一套模拟lambda的机制。其实我有点不明白C# 2.0为什么不直接引入lambda,而是先实现了anonymous method。可能有两个方面的原因,时间限制和用户教育。C# 3.0里可以说没有再使用anonymous method的必要了,lambda除了可以完全替代anonymous method外,还可以与编译器配合生成Expression Tree,也就是LINQ的根本。关于LINQ和Expression Tree,在讨论Query keywords会进一步涉及。
2. partial method
C#给大家主要的感觉是一门OO语言,一切都是对象,没有全局变量和全局函数。但是作为一门工业语言,只支持一种Paradigm是不够的。C# 1.0是OO的,2.0和3.0则增加了大量的functional programming和generative programming的功能,例如generic, lambda,partial class和partial method。虽然partial class和partial method对于团队开发有一定的帮助,但是其根本上还是为代码自动生成服务的。partial method是否有用,很多程度上取决于设计师在代码自动生成方面的设计,应用得当,可以提升团队的开发效率。
有几点限制:无返回值(void),不能有out参数,隐式声明为private(因此不能virtual),不能用于delegate。
3. 隐式类型推断
首先明确一点,C#是强类型语言,对于局部变量的隐式类型推断,仅仅是编译器帮你发现变量的类型。对简单类型(原生类型和非范型类型),用var是没多大意义的,甚至是不能鼓励的,应该使用显式类型和接口。随着范型引入.NET,对象的类型名会变得越来越长,如果看过boost里的lambda或者tuple的实现,就会理解范型带来的长类型名。LINQ的引入又加大了这种趋势,隐式类型推断在保证强类型的前提下,大大提高了代码的可读性和程序员的开发效率。
4. 匿名类型
匿名类型依旧是强类型,同样其最直接的用途也是LINQ。具备同样签名特征的匿名类型在不同的assembly是反复生成的,因此如果有明确的业务定义时,不建议使用匿名类型。LINQ返回的临时结果,或者实现特定接口的局部代码,使用匿名类型可以减少名字空间污染,提高可读性,降低出错几率。
5. 对象初始化和集合初始化
提升代码可读性和简洁的功能,不多介绍了。
6. 扩展方法
动态语言里有类型扩展的机制,例如Python里,类型也是对象,可以直接扩展类的方法,JavaScript通过Prototype扩展。C# 3.0对于类功能扩展的实现还是非常巧妙的,利用编译器实现,类似C++中的Templete也是由预处理器完成的。不违反开放封闭原则,可以实现比较好的代码可读性。
7. 自动实现的属性
把之前IDE实现的功能交给编译器实现了。不同于C/C++,有很多的编译器实现,C#的编译器控制在Microsoft手中,这样就有了编译器上改进的便捷。很多功能通过类库实现是非常复杂的,比如boost的lambda,而且可读性也较差,然而通过编译器或者预处理器(AspectJ),可以实现更好的效果。
有几点需要注意的,必须同时提供get和set,不能应用Attribute
8. 查询关键字
query keywords是为配合LINQ而产生的,这个是C# 3.0的功能中必须依赖.NET3.5的。编译器将query keyword生成为lambda和Expression Tree,这部分是可以编译器完成的,但是Expression Tree里的对象类型,都是在System.Core.dll中定义的,脱离了.NET 3.5的环境无法使用。当然也可以将几个dll直接拷贝到.NET的目标机器上运行,但是稳定性没有保证。
最后总结一下,工业级别的语言总是会不断演进的,C# 3.0, Python 3, C++ TR1, C99, PHP 5这些版本都带来了一些新的功能,这些功能到底有没有用?如果仅以功能实现为目标,那么用处不大,但是如果追求直观,优雅的设计,追求代码简洁可读,进而将Coding当成一门艺术时,语言的每个改进都带来的更多的可能性。驾驭这些新功能是需要一定的功力的,其前提是拥抱变化,欣而接受变化。如果自满于功能已实现,受限于自己的知识结构和设计习惯,是享受不到新功能带来的可能性的。