大家好,下面是我的一些小分享,详情请http://www.bdqn1.cn

 

 版本语言规格编译器C# 1.0December 2001January 2002C# 2.0December 2002November 2005C# 3.0June 2005November 2006C# 4.0June 2006in developC# 1.0,纯粹的面向对象  回溯到1998年底,微软正在忙于新一代COM的设计工作。此前,COM一直是组件化开发中非常成功的一种技术;但由于它仅提供了二进制层面上的统一,因此无法将类型信息和用于支持基础平台和开发工具的信息放到组件中。这时,Java正在逐步走向成熟。于是,微软学习Java的做法,将虚拟机的概念引入到了COM领域;同时,微软提出了“元数据”的概念,用于描述组件的类型信息和工具支持信息,并决定将其放入到组件当中。这种“COM虚拟机”的名字在经历了若干争论后,最终被定为CLR(Common Language Runtime,公共语言运行时)。与此同时,微软提出了在该运行时上运作的语言应该遵循的一些规则,以及该虚拟机的类型系统和指令集——所有这些规范形成了最终的C L I(Common Language Infrastructure,公共语言基础设施),并提交给了ECMA委员会。同时,微软开发了CLI的一个实现,这就是大名鼎鼎的.NET了。

  1998年12月,微软启动了一个全新的语言项目——COOL,这是一款专门为CLR设计的纯面向对象的语言,也正是本文的主角——C#的前身。历时半年有余,1999年7月份,微软完成了COOL语言的一个内部版本。直到2000年2月份,微软才正式将COOL语言更名为C#。据说起这个名字是因为C#开发小组的人很讨厌搜索引擎,因此把大部分搜索引擎无法识别的“#” 字符作为该语言名字的一部分;还有一种说法是在音乐当中“#”是升调记号,表达了微软希望它在C的基础上更上一层楼的美好愿望——当然这些都只是传说,无从考证。又是历经了一系列的修改,微软终于在2000年7月发布了C#语言的第一个预览版。因此人们一般认为C#是2000年发布的,并以此来计算它的“年龄”。在此后的一年多时间里,微软一直在修补各个测试版本中的BUG。直到2002年2月,微软终于推出了迟迟未上市的Visual Studio 7.0,并将其定名为“VisualStudio .NET 2002”。随着这套开发环境的出炉,开发者们终于看到了C#语言的第一个正式版本——C# 1.0。此后,微软马不停蹄,Visual Studio也恢复了往日的开发进度。在2003年5月,微软如期推出了Visual Studio .NET 2003,同时也发布了C#的改进版本——C# 1.1。
  这一时期的C#(以下称为C# 1.x)提出了纯粹的面向对象概念,并在语言特性中展现得淋漓尽致。C++并非纯面向对象的,为了和C兼容以及提供更高的执行效率,它保留了很多模块化的东西。Java尽管号称是面向对象的,但实际上,对于对象所应该具备的三种构成结构——属性、方法和事件,Java仅提供了方法,其它两种结构都要通过方法来模拟。在C# 1.x中,所有面向对象的概念都在语言中得到了非常好的体现。同时,C#还通过类类型、值类型和接口类型的概念形成了统一的类型系统。C#使用了大家所熟知的语法实现了方法,以至于很多人认为C#和Java、C++等面向对象语言“非常相像”,这使得从使用其他面向对象语言转到使用C#的过程非常简单。此外,C#还通过无参数列表的方法声名语法,结合get/set访问器实现了优雅的属性语法。其中的get访问器相当于获取属性值的方法,可以通过一些运算返回最终的结果,而不是简单地返回一个变量的值;而set访问器相当于设置属性值的方法,在其中可以进行一系列检测,最后将属性值赋给相应的变量。同时,通过同时提供get和set访问器、只提供get访问器和只提供set访问器,还可以很方便地实现可写、只读和只写的属性。C#的这种属性语法,使得一个属性在提供该属性的类的内部看来,非常像一组方法;而对于外部调用类看来,访问一个对象的属性和访问它的公共域没有任何区别。通过委托(稍后介绍),结合关键字event,C#提供了优雅的事件概念。使用+=运算符,开发者可以非常方便地将一个事件处理器关联到一个事件上,这个过程称之为“订阅”一个事件。由于委托内部封装了一个调用链表,因此可以方便地为一个事件添加多个事件处理器,这些处理器会自动地依次调用。多年的开发语言进化证明,函数指针是非常重要也是非常危险的语言特征之一。同时,基于函数指针的回调机制也Windows 核心概念之一。然而,由于函数指针很难验证参数的类型准确性,因此C#(确切地说是CLI)提出了“委托”的概念,这是一种类型安全的函数指针链表。这意味着,C#不仅可以提供回调机制,同时调用回调的一方还无需在其内部维护函数指针列表,所要做的仅仅是声名一个具有恰当委托类型的公共成员即可;而提供回调的一方也只需通过构造一个带有指定方法的相应委托实例,并通过“+=”运算符添加到回调列表即可。
  尽管C# 1.x提供了如此多的新鲜概念,但实际上,这些概念都是由CLI提出的。因此当将一个C#源程序编译为可执行文件时,编译器做的工作相对而言并不多。需要编译器代劳的是要将一个简单的委托定义语句翻译为一个继承System.MulticastDelegate类型C# 2.0,泛型编程新概念  微软本打算继续保证开发进度,并在2004年推出Visual Studio .NET 2004,但由于其间软件工程学尤
  

C#

其是软件管理学的大规模进步,微软所提供的这种仅具备开发和调试功能的IDE已经无法满足团队开发的需求。因此微软决定在项目设计和管理工具方面进行了进一步研发,并将其集成到Visual Studio中,以赢回原有的市场。因此,微软将 2004“改名”为Visual Studio 2005,并决定推迟一年发布。不过,微软还是坚持在2004年的6月份发布了Visual Studio2005的第一个Beta 版,同时向开发者展示了C#语言的2.0版本。2005年4月,微软发布了Visual Studio 2005 Beta2,这已经是具备了几乎全部功能的VisualStudio,包括的产品有SQL Server2005、Team Foundation Server和TeamSuite。这时的C#编译器已经能够处理C# 2.0中所有的新特性。
  C# 2.0为开发者带来的最主要的特性就是泛型编程能力。和面向对象思想一样,泛型思想也是一种已经成熟的编程思想,但依然是没有哪一种主流开发语言能够支持完备的泛型概念。这主要是因为泛型的概念在一定程度上对面向对象概念进行冲击,同时,由于在编译期间对类型参数的完全检测很难做到,很多问题会被遗留到运行时。C# 2.0别出心裁,对泛型类型参数提出了“约束”的新概念,并以优雅的语法体现在语言之中。有了约束,结合编译器强大的类型推断能力,可以在编译时发现几乎所有“危险”的泛型应用。C# 2.0的另一个突出的特性就是匿名方法,用来取代一些短小的并且仅出现一次的委托,使得语言结构更加紧凑。匿名方法除了可以使得事件处理器的编写更加精简以外,还将开发者带入了程序设计的一个新的领域——函数式编程,曾经有高人就用匿名方法结合泛型编程实现了函数式编程中的重要结构—— Lambda 表达式。尽管这种实现显得很繁琐而且不易理解,但毕竟是实现了。最终,函数式编程还是被引入到了C#语言中,这将在下一节中为大家讲述。
  此外,C# 2.0还进一步增强了语言的表达能力。在C# 2.0中,属性语法中的get和set访问器可以拥有不同的权限,这就使得定义一个在库的内部可读写,而在库的外部只读的属性成为可能。同时,C# 2.0还提供了迭代器的概念,这使得一个类无需实现IEnumerator 和IEnumerable接口即可实现一个可以进行遍历的类型,并且无需在类型中维护迭代状态。此时的.NET已经得到了很广泛的认可,并且因为元数据为组件带来了强大的自我描述能力,许多程序库厂商被吸引到.NET平台上来。随着.NET程序库数量的增长,逐渐暴露了命名的问题。在面向对象技术广泛发展后,人们就意识到名字的管理问题,因此几乎所有的面向对象语言都提出了“命名空间”的概念.而在C# 1.x时代,这个问题再一次出现。如果一个库厂商XX 希望以XX.System来命名他们自己的系统基础库,那么当开发者使用using System语句时就会产生歧义。为此。C# 2.0中提供了global关键字,这为.NET库中所有的命名空间提供了一个“根”,通过指定global::System和global::XX.System就可以区别两个库了。这一时期的C#编译器变得非常复杂,泛型的引入使得编译器不得不具备超强的类型推断能力。同时,迭代器的思想并非是在CLI层面上实现的,而是由编译器自动生成了实现I E n u m e r a t o r 和IEnumerable接口类型。在经历了一系列的改进和完善后,微软决定于2005年11月发布Visual Studio2005,该开发环境将正式支持C#2.0。由于此推出了数个预览版和测试版,大家的期待之情似乎已经不是那么强烈C#3.0(研发代号“Orcas”——魔鬼)  2005年9 月份的PDC大会则为开发者们带来了另外的惊喜——C#3.0(研发代号“Orcas”——魔鬼)的技术预览版。说到C# 3.0,就不得不提一下微软的LINQ 项目,LINQ(语言集成查询,Language Integrated Query)提出了一种通过面向对象语法来实现对非面向对象数据源的查询技术,可查询的数据源从关系型数据库延伸到一般意义上的集合(如数组和列表)以及XML。而C# 3.0则是率先实现了LINQ的语言。
  在C# 3.0中,我们可以用类似于SQL语句的语法从一个数据源中轻松地得到满足一定条件的对象集合。例如要查找一个字符串数组names中所有长度大于5的字符串,就可以写:
  var longname = from n in names wheren.Length > 5 select n;
  这样我们就得到一个新的字符数组longname,其中包含了我们所需要的结果。这种语句称作查询语句,与SQL语句唯一的区别是C#中的查询语句往往把select子句放到最后(这反而倒有些类似于中文的阅读顺序了)。初次看到这样一个语句,我们可能会有很大疑问:这还是C#语言吗?这的确是合乎语法规则的C#代码,而且编译器可以识别这种语法。然而实际上,C#编译器并不会对这种语法进行实际的的编译,而是将其翻译为正常的方法调用:
  var longname = names.Where(n => n.Length > 5).Select(n);
  

C#

  然后再进行进一步的编译。在上面的例子中已经说明,names是一个存放有字符串的数组,而数组类型并没有Where的方法。的确,Where并非names的成员方法,微软也没有对数组类型进行任何改动。这是C# 3.0中另外一个重要的新特性:扩展方法。扩展方法是定义在其他静态类中的静态方法,其第一个参数的类型就是希望扩展的类型,并且这个参数被冠以this修饰符。扩展方法是静态的,但可以像调用被扩展类型的实例方法那样进行调用,看起来好像是被扩展类型自己的方法一样。这就为语言带来了很大的灵活性,我们可以将一组近似的功能如上面的Where 和Select等(这在LINQ中被称作“标准查询表达式”)定义在一个外部类中,这样既无须修改现有类型,又可以将功能组织在一起。当然,为了做到面向对象的封装性,扩展方法只能在被扩展类型的公共成员上进行操作,如果需要从内部对类型进行改进,就必须改变现有类型的代码。在Where方法的参数列表里,我们又发现了一种奇怪的语法:n => n.Length > 5。这就是我们上文提到过的Lambda 表达式。
  微软的官方规范中称,Lambda 表达式是匿名方法的一种自然进化。因此Lambda 表达式其实也是一种特殊的委托,由编译器负责生成一个匿名的委托类型,它接受一个字符串类型的参数n;返回值为布尔类型,表示n的长度是否大于5;其中的参数类型和返回值类型都是由编译器推断而来的。说到类型推断,还要解释的一点
  

c# 本质论

就是上面的语句中出现的新关键字var。从出现的位置来看,var应该是一个类型。然而这又不是一个C#内建类型,也不是CLI提出的新类型;它只是一个“占位符”,它的确表示一个类型,但具体是什么类型需要编译器在编译期间进行推断。Lamda表达式的真正意义不仅仅在于简化了委托的编写方式,更重要的是它把代码表达式体现为了数据。换句话说,Lambda表达式不仅可以被编译为一段可以执行的代码(类似于匿名方法),也可以将其翻译为一个数据结构——表达式树。而如何处理Lambda 表达式,是由编译器根据Lambda表达式的使用方式来自动确定的。当把一个Lambda表达式赋给一个具有委托类型的域、属性或变量时,编译器像编译匿名方法一样将表达式体翻译成一段可执行代码;而当把一个L a m b d a 表达式赋给一个具有Expression<T>类型的域、属性或变量时,编译器就会将Lambda表达式解析为一个表达式树。对于翻译为代码的Lambda,可以向调用委托那样进行调用,而对于翻译为表达式树的Lambda表达式,就不可以了,会得到一个编译错误。但表达式树存在于一个由编译器生成的数据结构中,因此可以在运行时对其进行分析甚至修改。
  除了上面提到的一些重大改进之外,C# 3.0也对细微的语法进行了一些改进,使C#语言变得更加优雅和全面。值得说明的是,C# 3.0经过编译后生成的IL代码,完全是基于.NET 2.0的,C#语言已经远远跑在了他所栖生的平台前面。这一时期的C#语言离CLI已经越来越远了,编译器的工作也愈加繁重起来。首先很多语言结构(如查询表达式和Lambda 表达式)都不是CLI中提供的特性,因此需要编译器进行大量的转译工作;其次是这些语言结构带来的大量类型推断任务,也都是靠编译器来完成的。C#走到了3.0以后,已经完全不再是当年那个“简单”的语言了。它的开发者称其为“魔鬼”,而琳琅满目的新特性也的确让开发者们眼花缭乱,甚至感到恐惧。语言集成查询的引入,使得前一段时期内为开发者们广泛讨论的ORM概念得到了更加深入地体现,尤其是它所支持的数据源之广泛,让ORM理念变得已经不再必要了;而一些“.NET中的ORM实现”,似乎也成了完全不必要的扩展项目了。Lambda 表达式的引入,使得C#将可以轻松地完成特定领域(Domain-Specific)的开发。

  一个成功的开发人员在面对新鲜事物和新的困难时,兴奋是远大于恐惧的。让魔鬼来得更猛烈些吧!

本文摘自http://www.bdqn1.cn