1.2 回顾.NET历史
要更好地理解.NET和C#的可用功能,最好先了解它的历史。表1-1显示了.NET的版本、对应的公共语言运行库(Common Language Runtime, CLR)的版本、C#的版本和Visual Studio的版本,并指出相应版本的发布年份。除了知道使用什么技术之外,最好也知道不推荐使用什么技术,因为这些技术会被代替。
表1-1
下面各小节详细介绍表1-1,以及C#和.NET的发展。
1.2.1 C# 1.0 ——一种新语言
C# 1.0是一种全新的编程语言,用于.NET Framework。开发它时,.NET Framework由大约3000个类和CLR组成。
(创建Java的Sun公司申请)法庭判决不允许微软公司更改Java代码后,Anders Hejlsberg设计了C#。Hejlsberg为微软公司工作之前,在Borland公司设计了Delphi编程语言(一种Object Pascal语言)。Hejlsberg在微软公司负责J++(Java编程语言的微软版本)。鉴于Hejlsberg的背景,C#编程语言主要受到C++、Java和Pascal的影响。
因为C#的创建晚于Java和C++,所以微软公司分析了其他语言中典型的编程错误,完成了一些不同的工作来避免这些错误。这些不同的工作包括:
● 在if语句中,布尔(Boolean)表达式是必须的(C++也允许在这里使用整数值)。
● 允许使用struct和class关键字创建值类型和引用类型(Java只允许创建自定义引用类型;在C++中,struct和class之间的区别只是访问修饰符的默认值不同)。
● 允许使用虚拟方法和非虚拟方法 (这类似于C++, Java总是创建虚拟方法)。
当然,阅读本书,你会看到更多的变化。
现在,C#是一种纯粹的面向对象编程语言,具备继承、封装和多态性等特性。C#也提供了基于组件的编程改进,如委托和事件。
在.NET和CLR推出之前,每种编程语言都有自己的运行库。在C++中,C++运行库与每个C++程序链接起来。Visual Basic 6有自己的运行库VBRun。Java的运行库是Java虚拟机(Java Virtual Machine, JVC)——可以与CLR相媲美。CLR是每种.NET编程语言都使用的运行库。推出CLR时,微软公司提供了JScript .NET、Visual Basic .NET、 Managed C++和C#。JScript .NET是微软公司的JavaScript编译器,与CLR和.NET类一起使用。Visual Basic .NET是提供.NET支持的Visual Basic。现在再次简称为Visual Basic。Managed C++是混合了本地C++代码与Managed .NET代码的语言。今天与.NET一起使用的新C++语言是C++/ CLR。
.NET编程语言的编译器生成中间语言(Intermediate Language, IL)代码。IL代码看起来像面向对象的机器码,使用工具ildasm.exe可以打开包含.NET代码的DLL或EXE文件来检查IL代码。CLR包含一个即时(Just-In-Time, JIT)编译器,当程序开始运行时,JIT编译器会从IL代码生成本地代码。
注意:IL代码也称为托管代码。
CLR的其他部分是垃圾回收器(GC)、调试器扩展和线程实用工具。垃圾回收器负责清理不再引用的托管内存,这个安全机制使用代码访问安全性来验证允许代码做什么;调试器扩展允许在不同的编程语言之间启动调试会话 (例如,在Visual Basic中启动调试会话,在C#库内继续调试);线程实用工具负责在底层平台上创建线程。
.NET Framework的第1版已经很大了。类在名称空间内组织,以便于导航可用的3000个类。名称空间用来组织类,允许在不同的名称空间中有相同的类名,以解决冲突。.NET Framework的第1版允许使用Windows Forms(名称空间System.Windows.Forms)创建Windows桌面应用程序,使用ASP.NET Web Forms (System.Web )创建Web应用程序,使用ASP.NET Web Services与应用程序和Web服务通信,使用.NET Remoting在.NET应用程序之间更迅速地通信,使用Enterprise Services创建运行在应用程序服务器上的COM +组件。
ASP.NET Web Forms是创建Web应用程序的技术,其目标是开发人员不需要了解HTML和JavaScript。服务器端控件会创建HTML和JavaScript,这些控件的工作方式类似于Windows Forms本身。
C# 1.2和.NET 1.1主要是错误修复版本,改进较小。
注意:继承在第4章中讨论,委托和事件在第9章中讨论。
注意:.NET的每个新版本都有Professional C#图书的新版本。对于.NET 1.0,这本书已经是第2版了,因为第1版是以.NET 1.0的Beta 2为基础出版的。目前,本书是第10版。
1.2.2 带有泛型的C# 2和.NET 2
C# 2和.NET 2是一个巨大的更新。在这个版本中,改变了C#编程语言,建立了IL代码,所以需要新的CLR来支持IL代码的增加。一个大的变化是泛型。泛型允许创建类型,而不需要知道使用什么内部类型。所使用的内部类型在实例化(即创建实例)时定义。
C#编程语言中的这个改进也导致了Framework中多了许多新类型,例如System.Collections.Generic名称空间中新的泛型集合类。有了这个类,1.0版本定义的旧集合类就很少用在新应用程序中了。当然,旧类现在仍然在工作,甚至在新的.NET Core版本中也是如此。
注意:本书一直在使用泛型,详见第6章。第11章介绍了泛型集合类。
1.2.3 .NET 3.0 ——Windows Presentation Foundation
发布.NET 3.0时,不需要新版本的C#。3.0版本只提供了新的库,但它发布了大量新的类型和名称空间。Windows Presentation Foundation(WPF)可能是新框架最大的一部分,用于创建Windows桌面应用程序。Windows Forms包括本地Windows控件,且基于像素;而WPF基于DirectX,独立绘制每个控件。WPF中的矢量图形允许无缝地调整任何窗体的大小。WPF中的模板还允许完全自定义外观。例如,用于苏黎世机场的应用程序可以包含看起来像一架飞机的按钮。因此,应用程序的外观可以与之前开发的传统Windows应用程序非常不同。System.Windows名称空间下的所有内容都属于WPF,但System.Windows.Forms除外。有了WPF,用户界面可以使用XML语法设计XAML(XML for Applications Markup Language)。
.NET 3.0推出之前,ASP.NET Web Services和.NET Remoting用于应用程序之间的通信。Message Queuing是用于通信的另一个选择。各种技术有不同的优点和缺点,它们都用不同的API进行编程。典型的企业应用程序必须使用一个以上的通信API,因此必须学习其中的几项技术。WCF(Windows Communication Foundation)解决了这个问题。WCF把其他API的所有选项结合到一个API中。然而,为了支持WCF提供的所有功能,需要配置WCF。
.NET 3.0版本的第三大部分是Windows WF(Workflow Foundation)和名称空间System.Workflow。微软公司不是为几个不同的应用程序创建自定义的工作流引擎(微软公司本身为不同的产品创建了几个工作流引擎),而是把工作流引擎用作.NET的一部分。
有了.NET 3.0, Framework的类从.NET 2.0的8000个增加到约12000个。
注意:在本书中,WPF参见第29、30、31、34、35和36章。WCF详见第44章。
1.2.4 C# 3和.NET 3.5——LINQ
.NET 3.5和新版本C# 3一起发布。主要改进是使用C#定义的查询语法,它允许使用相同的语法来过滤和排序对象列表、XML文件和数据库。语言增强不需要对IL代码进行任何改变,因为这里使用的C#特性只是语法糖。所有的增强也可以用旧的语法实现,只是需要编写更多的代码。C#语言很容易进行这些查询。有了LINQ和lambda表达式,就可以使用相同的查询语法来访问对象集合、数据库和XML文件。
为了访问数据库并创建LINQ查询,LINQ to SQL发布为.NET 3.5的一部分。在.NET 3.5的第一个更新中,发布了Entity Framework的第一个版本。LINQ to SQL和Entity Framework都提供了从层次结构到数据库关系的映射和LINQ提供程序。Entity Framework更强大,但LINQ to SQL更简单。随着时间的推移,LINQ to SQL的特性在Entity Framework中实现了,并且Entity Framework会一直保留这些特性(现在它看起来与第一个版本非常不同)。
另一种引入为.NET 3.5一部分的技术是System.AddIn名称空间,它提供了插件模型。这个模型提供了甚至在过程外部运行插件的强大功能,但它使用起来也很复杂。
注意:LINQ详见第13章,Entity Framework的最新版本与.NET 3.5版本有很大差别,参见第38章。
1.2.5 C# 4和.NET 4.0——dynamic和TPL
C# 4的主题是动态集成脚本语言,使其更容易使用COM集成。C#语法扩展为使用dynamic关键字、命名参数和可选参数,以及用泛型增强的协变和逆变。
其他改进在.NET Framework中进行。有了多核CPU,并行编程就变得越来越重要。任务并行库(Task Parallel Library, TPL)使用Task类和Parallel类抽象出线程,更容易创建并行运行的代码。
因为用.NET 3.0创建的工作流引擎没有履行自己的诺言,所以全新的Windows Workflow Foundation成为.NET 4.0的一部分。为了避免与旧工作流引擎冲突,新的工作流引擎是在System.Activity名称空间中定义的。
C# 4的增强还需要一个新版本的运行库。运行库从版本2跳到版本4。
发布Visual Studio 2010时,附带了一项创建Web应用程序的新技术:ASP.NET MVC 2.0。与ASP.NET Web Forms不同,这项技术需要编写HTML和JavaScript,并使用C#和.NET的服务器端功能。ASP.NET MVC是定期更新的。
注意:C# 4的dynamic关键字参见第16章。任务并行库参见第21章。ASP.NET 5和ASP.NET MVC 6参见第40和41章。
1.2.6 C# 5和异步编程
C# 5只有两个新的关键字:async和await。然而,它大大简化了异步方法的编程。在Windows 8中,触摸变得更加重要,不阻塞UI线程也变得更加重要。用户使用鼠标,习惯于花些时间滚动屏幕。然而,在触摸界面上使用手势时,反应不及时很不好。
Windows 8还为Windows Store应用程序(也称为Modern应用程序、Metro应用程序、通用Windows应用程序,最近称为Windows应用程序)引入了一个新的编程接口:Windows运行库。这是一个本地运行库,看起来像是使用语言投射的.NET。许多WPF控件都为新的运行库重写了,.NET Framework的一个子集可以使用这样的应用程序。
System.AddIn框架过于复杂、缓慢,所以用.NET 4.5创建了一个新的合成框架:Managed Extensibility Framework和名称空间System.Composition。
独立于平台的通信的新版本是由ASP.NET Web API提供的。WCF提供有状态和无状态的服务,以及许多不同的网络协议,而ASP.NET Web API则简单得多,它是基于Representational State Transfer(REST)软件架构风格的。
注意:C# 5的async和await关键字在第15章中详细讨论。其中也介绍.NET在不同时期使用的不同异步模式。
MEF参见第26章。Windows应用程序参见第29~33章,ASP.NET Web API参见第42章。
1.2.7 C# 6和.NET Core
C# 6没有由泛型、LINQ和异步带来的巨大改进,但有许多小而实用的语言增强,可以在几个地方减少代码的长度。很多改进都通过新的编译器引擎Roslyn来实现。
注意:Roslyn参见第18章。
完整的.NET Framework并不是近年来使用的唯一.NET Framework。有些场景需要较小的框架。2007年,发布了Microsoft Silverlight的第一个版本(代码名为WPF/E,即WPF Everywhere)。Silverlight是一个Web浏览器插件,支持动态内容。Silverlight的第一个版本只支持通过JavaScript编程。第2个版本包含.NET Framework的子集。当然,不需要服务器端库,因为Silverlight总是在客户端运行,但附带Silverlight的框架Framework也删除了核心特性中的类和方法,使其更简洁,便于移植到其他平台。用于桌面的Silverlight最新版本(第5版)在2011年12月发布。Silverlight也用于Windows Phone的编程。Silverlight 8.1进入Windows Phone 8.1,但这个版本的Silverlight也不同于桌面版本。
在Windows桌面上,有如此巨大的.NET框架,需要更快的开发节奏,也需要较大的改进。在DevOps中,开发人员和操作员一起工作,甚至是同一个人不断地给用户提供应用程序和新特性,需要使新特性快速可用。由于框架巨大,且有许多依赖关系,创建新的特性或修复缺陷是一项不容易完成的任务。
有了几个较小的.NET Framework(如Silverlight、用于Windows Phone的Silverlight),在.NET的桌面版本和较小版本之间共享代码就很重要。在不同.NET版本之间共享代码的一项技术是可移植库。随着时间的推移,有了许多不同的.NET Framework和版本,可移植库的管理已成为一场噩梦。
为了解决所有这些问题,需要.NET的新版本(是的,的确需要解决这些问题)。Framework的新版本命名为.NET Core。.NET Core较小,带有模块化的NuGet包以及分布给每个应用程序的运行库是开源的,不仅可用于Windows的桌面版,也可用于许多不同的Windows设备,以及Linux和OS X。
为了创建Web应用程序,完全重写了ASP.NET Core 1.0。这个版本不完全向后兼容老版本,需要对现有的ASP.NET MVC(和ASP.NET MVC 6)代码进行一些修改。然而,与旧版本相比,它也有很多优点,例如每一个网络请求的开销较低,性能更好,也可以在Linux上运行。ASP.NET Web Forms不包含在这个版本中,因为ASP.NET Web Forms不是专为最佳性能而设计的,它基于Windows Forms应用程序开发人员熟悉的模式来提高开发人员的友好性。
当然,并不是所有的应用程序都很容易改为使用.NET Core。所以这个巨大的框架也会进行改进——即使这些改进的完成速度没有.NET Core那么快,也是要改进的。.NET Framework完整的新版本是4.6。ASP.NET Web Forms的小更新包在完整的.NET上可用。
注意:Roslyn参见第18章。C#语言的变化参见第Ⅰ部分中所有的语言章节,例如,只读属性参见第3章,nameof运算符和空值传播参见第8章,字符串插值参见第10章,异常过滤器参见第14章。本书尽可能使用.NET Core。.NET Core和NuGet包的更多信息参见本章后面的内容。
1.2.8 选择技术,继续前进
知道框架内技术相互竞争的原因后,就更容易选择用于编写应用程序的技术。例如,如果创建新的Windows应用程序,使用Windows Forms就不好。而应该使用基于XAML的技术,例如Windows应用程序,或者使用WPF的Windows桌面应用程序。
如果创建Web应用程序,肯定应使用ASP.NET Core与ASP.NET MVC 6。做这个选择时要排除ASP.NET Web Forms。如果访问数据库,就应该使用Entity Framework而不是LINQ to SQL,应该选择Managed Extensibility Framework而不是System.AddIn。
旧应用程序仍在使用Windows Forms、ASP.NET Web Forms和其他一些旧技术。只为改变现有的应用程序而使用新技术是没有意义的。进行修改必须有巨大的优势,例如,维护代码已经是一个噩梦,需要大量的重构以缩短客户要求的发布周期,或者使用一项新技术可以减少更新包的编码时间。根据旧有应用程序的类型,使用新技术可能不值得。可以允许应用程序仍使用旧技术,因为在未来的许多年仍将支持Windows Forms和ASP.NET Web Forms。
本书的内容以新技术为基础,展示创建新应用程序的最佳技术。如果仍然需要维护旧应用程序,可以参考本书的老版本,其中介绍了ASP.NET Web Forms、Windows Forms、System.AddIn和其他仍然在.NET Framework中可用的旧技术。