1.1 .NET Framework的含义
.NET Framework(现在是版本4.5)是Microsoft为开发应用程序而创建的一个具有革命意义的平台。这句话*有趣的地方在于它的广义性,但这是有原因的。首先,注意这句话没有说“在Windows操作系统上开发应用程序”。尽管.NET Framework的Microsoft版本运行在Windows操作系统和Windows Phone操作系统上,但它也有运行在其他操作系统上的版本,例如Mono,它是.NET Framework的开源版本(包含C#编译器),该版本可以运行在几个操作系统上,包括各种Linux版本和Mac OS。另外,Mono还有一些版本可以运行在iPhone(MonoTouch)和Android(Mono for Android,也称为MonoDroid)智能手机上。使用.NET Framework的一个重要原因是它可以作为集成各种操作系统的方式。
另外,上面给出的.NET Framework定义并未限制应用程序的类型。这是因为本来就没有限制。可以使用.NET Framework创建桌面应用程序、Windows Store应用程序、Web应用程序、Web服务和其他各种类型的应用程序。另外注意,对于Web应用程序,按照定义,它们是多平台的应用程序,因为任何带有Web浏览器的系统都可以访问它们。
.NET Framework的设计方式确保它可以用于各种语言,包括本书介绍的C#语言,以及C++、Visual Basic、JScript甚至一些旧语言,如COBOL。为此,还推出了这些语言的.NET版本,目前还在不断推出更多版本。所有这些语言都可以访问.NET Framework,它们彼此之间还可以通信。C#开发人员可以使用Visual Basic程序员编写的代码,反之亦然。
所有这些提供了意想不到的多样性,这也是.NET Framework具有诱人前景的部分原因。
1.1.1 .NET Framework的内容
.NET Framework主要包含一个庞大的代码库,可以在客户语言(如C#)中通过面向对象编程技术(OOP)来使用这些代码。这个库分为多个不同的模块,这样就可以根据希望得到的结果来选择使用其中的各个部分。例如,一个模块包含Windows应用程序的构件,另一个模块包含网络编程的代码块,还有一个模块包含Web开发的代码块。一些模块还分为更具体的子模块,例如,在Web开发模块中,有用于建立Web服务的子模块。
其目的是,不同操作系统可以根据各自的特性,支持其中的部分或全部模块。例如,智能手机支持所有的核心.NET功能,但不需要某些更**的模块。
部分.NET Framework库定义了一些基本类型。类型是数据的一种表达方式,指定*基本类型(如32位带符号的整数)有助于使用.NET Framework的各种语言之间进行交互操作。这称为通用类型系统(Common Type System,CTS)。
除提供这个库外,.NET Framework还包含.NET公共语言运行库(Common Language Runtime,CLR),它负责管理用.NET库开发的所有应用程序的执行。
1.1.2 使用.NET Framework编写应用程序
使用.NET Framework编写应用程序,就是使用.NET代码库编写代码(使用支持Framework的任何一种语言)。本书用VS进行开发,VS是一种强大的集成开发环境,支持C#(以及托管和非托管C++、Visual Basic和其他一些语言)。这个环境的优点是便于把.NET功能集成到代码中。我们创建的代码完全是C#代码,但使用了.NET Framework,并在需要时利用了VS中的其他工具。
为执行C#代码,必须把它们转换为目标操作系统能够理解的语言,即本机代码(native code)。这种转换称为编译代码,由编译器执行。但在.NET Framework下,此过程包括两个阶段。
1. CIL和JIT
在编译使用.NET Framework库的代码时,不是立即创建专用于操作系统的本机代码,而是把代码编译为通用中间语言(Common Intermediate Language,CIL)代码,这些代码并非专门用于任何一种操作系统,也非专门用于C#。其他.NET语言,如Visual Basic .NET也会在**阶段编译为这种语言。开发C#应用程序时,这个编译步骤由VS完成。
显然,要执行应用程序,必须完成更多工作,这是Just-In-Time(JIT)编译器的任务,它把CIL编译为专用于OS和目标机器结构的本机代码。这样OS才能执行应用程序。这里编译器的名称Just-In-Time反映了CIL代码仅在需要时才编译的事实。这种编译可以在应用程序的运行过程中动态发生,不过开发人员一般不需要关心这个过程。除非要编写性能十分关键的代码,否则知道这个编译过程会在后台自动进行,并不需要人工干预就可以了。
过去,常常需要把代码编译为几个应用程序,每个应用程序都用于特定的操作系统和CPU结构。这通常是一种优化形式(例如,为了让代码在AMD芯片组上运行得更快),有时则是非常重要的(例如,使应用程序可以同时工作在Win9x和WinNT/2000环境下)。现在就不必要了,因为JIT编译器使用CIL代码,而CIL代码是独立于计算机、操作系统和CPU的。目前有几种JIT编译器,每种编译器都用于不同的结构,CIL会使用合适的编译器创建所需的本机代码。
这样,开发人员需要做的工作就比较少了。实际上,可以忽略与系统相关的细节,将注意力集中在代码的功能上就够了。
2. 程序集
在编译应用程序时,所创建的CIL代码存储在一个程序集中。程序集包括可执行的应用程序文件(这些文件可以直接在Windows上运行,不需要其他程序,其扩展名是.exe)和其他应用程序使用的库(其扩展名是.dll)。
除包含CIL外,程序集还包含元信息(即程序集中包含的数据的信息,也称为元数据)和可选的资源(CIL使用的其他数据,例如,声音文件和图片)。元信息允许程序集是完全自描述的。不需要其他信息就可以使用程序集,也就是说,我们不会遇到没有把需要的数据添加到系统注册表中这样的问题,而这在使用其他平台进行开发时这个问题常常出现。
因此,部署应用程序就非常简单了,只需把文件复制到远程计算机上的目录下即可。因为不需要目标系统上的其他信息,所以只需从该目录中运行可执行文件即可(假定安装了.NET CLR)。
当然,不必把运行应用程序需要的所有信息都安装到一个地方。可以编写一些代码来执行多个应用程序所要求的任务。此时,通常把这些可重用的代码放在所有应用程序都可以访问的地方。在.NET Framework中,这个地方是全局程序集缓存(Global Assembly Cache,GAC),把代码放在这个缓存中是很简单的,只需把包含代码的程序集放在包含该缓存的目录中即可。
3. 托管代码
在将代码编译为CIL,再用JIT编译器将它编译为本机代码后,CLR的任务尚未全部完成,还需要管理正在执行的用.NET Framework编写的代码(这个执行代码的阶段通常称为运行时(runtime))。即CLR管理着应用程序,其方式是管理内存、处理**性以及允许进行跨语言调试等。相反,不受CLR控制运行的应用程序属于非托管类型,某些语言(如C++)可以用于编写此类应用程序,例如,访问操作系统的低级功能。但是在C#中,只能编写在托管环境下运行的代码。我们将使用CLR的托管功能,让.NET处理与操作系统的任何交互。
4. 垃圾回收
托管代码*重要的一个功能是垃圾回收(garbage collection)。这种.NET方法可确保应用程序不再使用某些内存时,就会完全释放这些内存。在.NET推出以前,这项工作主要由程序员负责,代码中的几个简单错误会把大块内存分配到错误的地方,使这些内存神秘失踪。这通常意味着计算机的速度逐渐减慢,*终导致系统崩溃。
.NET垃圾回收会定期检查计算机内存,从中删除不再需要的内容。执行垃圾回收的时间并不固定,可能一秒钟内会进行数千次的检查,也可能几秒钟才检查一次,不过一定会进行检查。
这里要给程序员一些提示。因为在不可预知的时间执行这项工作,所以在设计应用程序时,必须留意这一点。需要许多内存才能运行的代码应自己完成清理工作,而不是坐等垃圾回收,但这不像听起来那样难。
5. 把它们组合在一起
在继续学习之前,先总结一下上述创建.NET应用程序所经历的步骤:
(1) 使用某种.NET兼容语言(如C#)编写应用程序代码,如图1-1所示。
(2) 把代码编译为CIL,存储在程序集中,如图1-2所示。
图 1-1 图 1-2
(3) 在执行代码时(如果这是一个可执行文件,就自动运行,或者在其他代码使用它时运行),首先必须使用JIT编译器将代码编译为本机代码,如图1-3所示。
图 1-3
(4) 在托管的CLR环境下运行本机代码,以及其他应用程序或进程,如图1-4所示。
图 1-4
6. 链接
在上述过程中还有一点要注意。在第(2)步中编译为CIL的C#代码未必包含在单独文件中,可以把应用程序代码放在多个源代码文件中,再把它们编译到一个程序集中。这个过程称为链接(linking),是非常有用的。原因是处理几个较小的文件比处理一个大文件要简单得多。可以把逻辑上相关的代码分解到一个文件中,以便单独进行处理,这也更便于在需要时找到特定的代码块,让开发小组把编程工作分解为一些可管理的块,让每个人编写一小块代码,而不会破坏已编写好的代码部分或其他人正在处理的部分。
1.2 C#的含义
如上所述,C#是可用于创建要运行在.NET CLR上的应用程序的语言之一,它从C和C++语言演化而来,是Microsoft专门为使用.NET平台而创建的。因为C#是近期发展起来的,所以吸取了以往的教训,考虑了其他语言的许多优点,并解决了它们的问题。
使用C#开发应用程序比使用C++简单,因为其语法更简单。但是,C#是一种强大的语言,在C++中能完成的任务几乎都能利用C#完成。虽然如此,C#中与C++**功能等价的功能(例如直接访问和处理系统内存),只能在标记为“unsafe”的代码中使用。这个**编程技术存在潜在威胁(正如它的名称所暗示的),因为它可能覆盖系统中重要的内存块,导致严重后果。因此,本书不讨论这个问题。
C#代码常比C++略长一些。这是因为C#是一种类型**的语言(与C++不同)。在外行人看来,这表示一旦为某个数据指定了类型,就不能转换为另一个不相关的类型。所以,在类型之间转换时,必须遵守严格的规则。执行相同的任务时,用C#编写的代码通常比用C++编写的代码长。但C#代码更健壮,调试起来也比较简单,.NET始终可以随时跟踪数据的类型。在C#中,不能完成诸如“把4字节的内存分配给这个数据后,我们使其有10个字节长,并把它解释为X”等任务,但这并不是一件坏事。
C#只是用于.NET开发的一种语言,但它是*好的一种语言。C#的优点是,它是**彻头彻尾为.NET Framework设计的语言,是在移植到其他操作系统上的.NET版本中使用的主要语言。要使诸如VB.NET的语言尽可能类似于其以前的语言,且仍遵循CLR,就不能完全支持.NET代码库的某些功能,至少需要不常见的语法。但C#能使用.NET Framework代码库提供的每种功能。而且,.NET的每个新版本都在C#语言中添加了新功能,满足了开发人员的要求,使之更强大。
1.2.1 用C#能编写什么样的应用程序
如前所述,.NET Framework没有限制应用程序的类型。C#使用的是.NET Framework,所以也没有限制应用程序的类型。这里仅讨论几种常见的应用程序类型。
桌面应用程序 这些应用程序(如Microsoft Office)具有我们很熟悉的Windows外观和操作方式,使用.NET Framework的Windows Presentation Foundation(WPF)模块就可以简便地生成这种应用程序。WPF模块是一个控件库,其中的控件(例如按钮、工具栏和菜单等)可用于建立Windows用户界面(UI)。
Windows Store应用程序 这是Windows 8中新引入的一类应用程序。此类应用程序主要针对触摸设备设计,通常全屏运行,侧**在于简洁清晰。创建这类应用程序的方式有多种,包括使用WPF。
Web应用程序 它们是一些Web页面,可以通过任何Web浏览器查看。.NET Framework包括一个动态生成Web内容的强大系统,允许进行个性化和实现**性等。这个系统称为Active Server Pages .NET(ASP.NET),我们可以使用C#通过Web Forms 创建ASP.NET应用程序。还可以使用Silverlight编写在浏览器内部运行的应用程序。
WCF服务 这是一种灵活创建各种分布式应用程序的方式。使用WCF服务可以通过局域网或Internet交换几乎各种数据。无论使用什么语言创建WCF服务,也无论WCF服务驻留在什么系统上,都使用一样简单的语法。
这些类型的应用程序也可能需要某种形式的数据库访问,这可以通过.NET Framework的Active Data Objects .NET(ADO.NET)部分、ADO.NET Entity Framework或C#的LINQ(Language Integrated Query)功能来实现。也可以使用许多其他资源,例如,创建联网组件、输出图形、执行复杂数学任务的工具。
1.2.2 本书中的C#
本书第Ⅰ部分介绍C# 语言的语法和用法,但不过分强调.NET Framework。这是必需的,因为我们不能没有一点儿C# 编程基础就使用.NET Framework。首先介绍一些比较简单的内容,把较复杂的面向对象编程(Object-Oriented Programming,OOP)论题放在基础知识的后面论述。假定读者没有一点儿编程的知识,这些是首要的规则。
学习了基础知识后,本书还将介绍如何开发更复杂、更有用的应用程序。本书的第Ⅱ部分将讨论桌面和Windows Store应用程序编程,第Ⅲ部分将研究Web应用程序编程,第Ⅳ部分将讲述数据访问(对数据库、文件系统和XML数据的访问)和LINQ,第Ⅴ部分将介绍其他一些有趣的.NET论题。
1.3 Visual Studio 2012
本书使用Visual Studio 2012开发工具进行所有的C#编程,包括简单的命令行应用程序,乃至较复杂的项目类型。VS不是开发C#应用程序所必需的开发工具或集成开发环境(IDE),但使用它可以使任务更简单一些。如果愿意的话,可在基本的文本编辑器(如常见的记事本)中处理C#源代码文件,再使用.NET Framework中包含的命令行编译器把代码编译到程序集中。但是,为什么不使用功能完备的IDE呢?
下面列出一些使VS成为.NET开发**工具的功能。
VS可以自动执行编译源代码的步骤,同时可以完全控制编译过程中使用的任何选项。
VS文本编辑器为VS支持的语言(包括C#)量身定制,这样就可以智能检测错误,在输入代码时给出合适的**代码,这个功能称为IntelliSense。
VS包括XAML、ASP.NET及其他UI语言的设计器,允许UI元素的简单拖放设计。
在C#中,许多类型的项目都可用已有的“样板”代码来创建,不需要从头开始。各种代码文件通常已经准备好了,减少了从头开始一个项目所用的时间。
VS包括几个可自动执行常见任务的向导,其中很多任务可在已有的文件中添加合适的代码,在某些情况下,你甚至不需要考虑语法的正确性。
VS包含许多强大的工具,可以显示项目中的元素并允许在其中导航,这些元素可以是C#源代码文件,也可以是其他资源,例如位图图像或声音文件。
除了在VS中编写应用程序外,还可以创建部署项目,以便为客户提供代码,并使客户方便地完成安装。
在开发项目时,VS允许使用**调试技巧,例如,能在代码中一次调试一条指令,并监视应用程序的状态。
C#还有许多功能,希望读者能掌握它们!
1.3.1 Visual Studio Express 2012产品
除Visual Studio 2012外,Microsoft还提供了几个更简单的开发工具,称为Visual Studio Express 2012产品。可以在http://www.microsoft.com/express上免费获得它们。
各种Express产品可以创建所需的几乎所有C#应用程序。在功能上它们都是VS的删节版本,但外观和操作方式是一样的。尽管它们提供了VS的许多功能,但缺少一些重要功能;不过我们仍可以在学习本书的过���中使用它们。
1.3.2 解决方案
在使用VS开发应用程序时,可以通过创建解决方案来完成。在VS术语中,解决方案不仅是一个应用程序,它还包含项目,可以是WPF项目和Web应用程序项目等。但是,解决方案可以包含多个项目,这样,即使相关的代码*终在硬盘上的多个位置编译为多个程序集,也可以把它们组合到一个地方。
这是非常有用的,因为它可以处理“共享”代码(这些代码放在GAC中),同时,应用程序也使用这段共享代码。在使用**的开发环境时,调试代码是非常容易的,因为可以在多个代码块中单步调试指令。
1.4 小结
本章简要介绍了.NET Framework,并讨论了如何轻松创建各种功能强大的应用程序。还探讨了把用C#等语言编写的代码转换为可运行的应用程序所需要做的工作,以及使用在.NET公共语言运行库下运行的托管代码有什么优点。
本章还阐述了C#的实质,以及它与.NET Framework的关系,描述了进行C#开发时所使用的工具Visual Studio 2012。
第2章将介绍如何运行一些C#代码,介绍基础知识,并集中讨论C#语言本身,而不是过多地讨论IDE的工作原理。