在实战中成长:Windows Forms开发之路
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.1 .NET的概念

1.1.1 什么是.NET

对于.NET,微软官方有如下描述:

“.NET是微软的用以创建XML Web服务(下一代软件)平台,该平台将信息、设备和人以一种统一的、个性化的方式联系起来。”

“借助于.NET平台,可以创建和使用基于XML的应用程序、进程和Web站点以及服务,它们之间可以按设计在任何平台或智能设备上共享和组合信息与功能,以向单位和个人提供定制好的解决方案。”

“.NET是一个全面的产品家族,它建立在行业标准和Internet标准之上,提供开发(工具)、管理(服务器)、使用(构造块服务和智能客户端)以及XML Web服务体验(丰富的用户体验)。.NET将成为你今天正在使用的微软应用程序、工具和服务器的一部分,同时,新产品不断扩展XML Web的服务能力以满足你的所有业务需求。”

发布.NET之后,盖茨说,网络将由呈现式的平台转为完全的平台。

.NET是一个平台,是微软的XML Web服务平台。XML Web services允许应用程序通过互联网进行通信和共享数据,而不管所采用的是哪种操作系统、设备或编程语言。.NET平台提供创建XML Web services并将这些服务集成在一起所需的全部工具。这个平台包含广泛的产品系列,它们都是基于XML和Internet行业标准构建,提供从开发、管理、使用到体验XML Web服务的各个方面的产品。现在,微软正在五个方面创建.NET平台,即工具、服务器、XML Web服务、客户端和.NET体验。

事实上,很早就有人提出过,对计算机发展和普及做出巨大贡献的软件行业已经到了这样一个转折点:留在终端的软件会越来越少,目前通过软件包发行的方式即将消失,而改为网上出租的形式获得利润,用户只要在本地发出请求,就可以在网上直接使用它,而这个软件的供应商会以你使用的次数来收费。一旦这个设想成为现实,集成诸多功能的浏览器将取代现在操作系统的地位,成为终端上唯一需要预安装的软件。

.NET还是微软的一个互联网之梦,是微软公司提出的下一代互联网构想。在这一构想中,计算超越了网络浏览,进入一个更为先进的互联网平台和极为丰富的软件服务的新世界。微软心中有一个梦想,它要通过.NET改变人们未来的生活方式。就像当年Windows的出现使电脑从精英手中的玩具变成了普通大众身边不可或缺的工具,.NET极有可能会使互联网成为人们生活中密不可分的一部分。在未来的信息时代,人们的生活、工作、学习、娱乐,都将得到.NET的帮助。到那个时候,.NET或许不会有人再提起,但是它带来的产品与概念,却将时刻伴随我们左右。

1.1.2 .NET Framework

.NET Framework是一种全新的运算平台,它提供了在Windows操作系统执行应用程序所需的服务,以及相关的应用程序接口,其中包含了两个主要部分:Common Language Runtime(公共语言运行库)以及.NET Framework类库(Class Library),分别列举说明如下:

Common Language Runtime简称CLR,其本身可以用于执行程序代码管理及机制,其中提供了各种服务,例如,多线程管理、内存管理及类型检查等,应用程序的源代码在这样的机制下,确保了其安全性与正确性。

Common Language Runtime是.NET Framework的基础,控制和管理程序代码的运作,建立在CLR上所执行的程序代码被称为托管(Managed)的程序代码。一般来说,在.NET Framework中所编写的应用程序均必须在CLR的环境下执行,也因此受到CLR的监控,本身均为托管代码。

其他无法在CLR环境下执行的程序代码,我们则将其称为托管(Unmanaged)的程序代码,例如,.NET出现之前的Visual Basic 6.0、C++等,均属于这一类的程序代码。

类库(Class Library)包含了以面向对象理论设计、提供开发应用程序所需功能的各种类型,其涵盖的功能相当广泛,从最基本的数据流I/O,创建丰富用户接口所需的应用程序接口、多线程应用程序的编写,到提供复杂的分布式远程服务应用程序开发,程序开发人员几乎都可以在其中找到相关的支持。

1.1.3 Common Language Runtime

公共语言运行库的功能通过编译器和工具公开,你可以编写利用此托管执行环境的代码。使用基于公共语言运行库的语言编译器开发的代码称为托管代码。托管代码具有许多优点,例如:跨语言集成、跨语言异常处理、增强的安全性、版本控制和部署支持、简化的组件交互模型、调试和分析服务等。

若要使公共语言运行库能够向托管代码提供服务,语言编译器必须生成一些元数据来描述代码中的类型、成员和引用。元数据与代码一起存储,每个可加载的公共语言运行库可移植执行(PE)文件都包含元数据。公共语言运行库使用元数据来完成以下任务:查找和加载类、在内存中安排实例、解析方法调用、生成本机代码、强制安全性,以及设置运行时上下文边界。

公共语言运行库自动处理对象布局并管理对象引用,当不再使用对象时释放它们。按这种方式实现生存期管理的对象称为托管数据。垃圾回收消除了内存泄漏以及其他一些常见的编程错误。如果你编写的代码是托管代码,则可以在.NET Framework应用程序中使用托管数据、非托管数据或者同时使用这两种数据。由于语言编译器会提供自己的类型(如基元类型),因此你可能并不知道(或需要知道)这些数据是否是托管的。

有了公共语言运行库,就可以很容易地设计出对象能够跨语言交互的组件和应用程序。也就是说,用不同语言编写的对象可以互相通信,并且它们的行为可以紧密集成。例如,可以定义一个类,然后使用不同的语言从原始类派生出另一个类或调用原始类的方法。还可以将一个类的实例传递到用不同的语言编写的另一个类的方法。这种跨语言集成之所以成为可能,是因为基于公共语言运行库的语言编译器和工具使用由公共语言运行库定义的通用类型系统,而且它们遵循公共语言运行库关于定义新类型以及创建、使用、保持和绑定到类型的规则。

所有托管组件都带有生成它们所基于的组件和资源的信息,这些信息构成了元数据的一部分。公共语言运行库使用这些信息确保组件或应用程序具有它需要的所有内容的指定版本,这样就使代码不太可能由于某些未满足的依赖项而发生中断。注册信息和状态数据不再保存在注册表中(因为在注册表中建立和维护这些信息很困难)。取而代之的是,有关你定义的类型(及其依赖项)的信息作为元数据与代码存储在一起,这样大大降低了组件复制和移除任务的复杂性。

下面是公共语言运行库的一些优点:

● 性能得到了改进。

● 能够轻松使用其他语言开发的组件。

● 类库提供的可扩展类型。

● 新的语言功能,如面向对象的编程的继承、接口和重载;允许创建多线程的可缩放应用程序的显式自由线程处理支持;结构化异常处理和自定义属性支持。

如果使用Microsoft Visual C++.NET,则可以使用C++托管扩展来编写托管代码。C++托管扩展提供了托管执行环境以及对你所熟悉的强大功能和富于表现力的数据类型的访问等优点。其他公共语言运行库功能包括:

● 跨语言集成,特别是跨语言继承。

● 垃圾回收,它管理对象生存期,使引用计数变得不再必要。

● 自我描述的对象,它使得使用接口定义语言(IDL)不再是必要的。

● 编译一次即可在任何支持公共语言运行库的CPU和操作系统上运行的能力。

还可以使用C#语言编写托管代码。C#语言具有以下优点:

● 完全面向对象的设计。

● 非常强的类型安全。

● 很好地融合了Visual Basic的简明性和C++的强大功能。

● 垃圾回收。

● 类似于C和C++的语法和关键字。

● 使用委托取代函数指针,从而增强了类型安全和安全性。函数指针通过unsafe C#关键字和C#编译器(csc.exe)的/unsafe选项可用于非托管代码和数据。

1.1.4 .NET Framework类库

类库包含了功能广泛的各种类型,我们必须知道的是,类型为创建于.NET平台上执行的应用程序的基础元素,整个类库包含的类型,按其功能大致可以分为以下几类:

提供基础数据的相关类型。其中包含了类型之间的转换操作、格式化以及字符串数据处理等相关功能。

使用于应用程序的异常处理机制。用于在应用程序执行期间提供一致性的错误处理机制,其中包含了异常返回及错误的捕捉。

执行期查看加载的类型信息。提供执行期间,应用程序加载类型信息的查看与创建类型执行实例(Instance),并且针对这些执行期间动态产生的类型实例,进行调用(Invoke)以及存取操作。

封装数据结构。提供如对象集合、数组、字典以及散列表等相关数据结构的实现。

I/O流的操作。允许针对数据流和文件进行读取和写入操作,其中文件包含了文件夹路径、磁盘盘符等。数据流对于各种存储器,支持缓冲写入和读取字节的操作,其中包含了如网络流、内存流等数据流。

提供数据存取。允许程序设计人员使用其所提供的数据存取服务,进行各种数据库的数据维护操作,这方面的功能由一组ADO.NET所提供的组件完成。

制作丰富的用户界面。包含制作窗口界面、绘图功能的相关类型。

1.1.5 编写第一个.NET程序

C#是一种专为.NET Framework所设计的面向对象程序语言,使用了CLR提供的服务,创建解决特定问题的应用程序,它是C++经过改良,以面向对象设计理论为基础发展而来的,特别是在语法上,C#大致继承了C++的风格,另一方面也同时弥补了C++的欠缺和不足的功能,比如增加了类型安全、版本控制、事件和内存回收等机制。

C#被设计成为比起过去你所学习的程序语言(例如C++)功能更为强大,并且具有如Visual Basic等程序语言容易使用的优点,由于其完整的面向对象特性以及本身与类库的紧密结合,使得开发功能强大的商业级应用程序更为容易;C#应用程序本身由一个以上分开的程序代码文件所组成,其扩展名为“cs”。最简单的C#程序代码文件可以使用记事本之类的文本编辑器,经过将其保存为“.cs”扩展名的文件来完成。

C#编译器提供将程序文件编译成为可执行文件(扩展名为“.exe”)的功能,C#编译器名称为csc.exe,你可以在命令行输入可执行文件名称启动这个编译器,进行程序的编译操作。

以下内容,我们将从一个简单的程序范例开始,介绍使用C#程序语言所必须了解的相关知识,并且说明其基本用法。

编写一个简单的C#应用程序并不困难,如同一般学习程序语言的书籍一样,我们使用一个简单的HelloWorld应用程序,作为C#程序语言探讨的起点。打开Notepad文本编辑器,输入以下范例程序代码:

     // HelloWorld.cs
     //---------------------------------------------------------------------
     //HelloWorld应用程序
     //---------------------------------------------------------------------
     class HelloWorld
     {
       static void Main()
         {
             System.Console.WriteLine("Hello World");
         }
     }

完成后,将其扩展名改为“.cs”,并且以“HelloWorld”名称存盘。接下来,将C#程序代码文件编译成为可执行文件。你可以有几种方法完成编译操作。其中最简单的方法是使用命令行,然而,前提是使用的计算机上必须安装了.NET Framework。你可以从微软公司的网站取得完整的.NET Framework安装程序,根据其提示,完成安装操作。现在假设你的计算机上已完成相关的环境设置,在命令行窗口输入以下命令:

     csc HelloWorld.cs

其中“csc”是C#编译器的名称,“HelloWorld.cs”则是所要编译的C#程序代码文件,执行此编译命令,产生一个扩展名为“.exe”的HelloWorld可执行文件,用鼠标双击即可执行文件,得到的结果如图1.1所示。

图1.1 运行结果

一个能够在主控制台输出制定文字信息的应用程序就这样完成了,这个程序虽然简单,但是其中包含了编写C#应用程序所需了解的一些基础知识。我们现在利用这个范例程序代码,说明C#程序语言的一些重要基础知识。

1.注释

注释被应用于程序语言中,说明注记程序代码的内容。善用注释,可以增强应用程序的可读性,尤其是当你所开发的应用程序愈来愈大的时候,注释能够帮你很快地了解自己先前写下的程序代码内容所代表的真正意义。因此,为你所编写的程序提供充分的注释,是一种良好且必需的程序设计编写习惯。由于注释知识用于说明程序代码的相关文字,因此编译器不会去理解注释的内容,C#提供了与C++语言相同的注释符号,例如,在上述范例程序中,一开始的程序代码:

     // HelloWorld.cs
     //---------------------------------------------------------------------
     //HelloWorld应用程序
     //---------------------------------------------------------------------

这4行程序代码均以两条正斜线开始,将其标示为注释,C#另外提供了一种标示整段的注释符号,可以将上述代码修改如下:

     /* HelloWorld.cs
     -----------------------------------------------------------------------
     HelloWorld应用程序
     ---------------------------------------------------------------------*/

这种形式的注释由“/*”以及“*/”两个符号组成,落在这个两个符号里的文字内容将会被当作注释,而与程序代码的内容无关。

2.类声明

HelloWorld范例程序代码的注释后面,紧接着是类的声明。类在C#中被用来定义用户自行创建的引用类型,C#应用程序均是由不同的类型所组成,而类则是一种特定类型。应用程序的相关程序代码,都必须被写在类里面,而要创建一个类,首先必须声明此类,如范例中的程序代码:

     class HelloWorld

这一行的语句声明一个称为HelloWorld的新类,并且用括号“{}”界定其程序代码的内容,在控制台输出“Hello World”信息的相关程序代码均被写在这里面。大括号中创建了一个程序代码块,其中存在着一行以上的程序代码语句,形成了一个程序的逻辑单位,这些单位在程序执行的时候,根据程序员组织的方式进行运算,让你能够有效且清楚地执行程序运算。

3.程序入口点Main()

大括号{}里的程序代码,包含了一个函数Main,其代表一个类所能提供的方法。方法定义了类所能执行的工作,也决定了类的特性。一个类可以用数种不同的方法,方法的详细内容我们将在后续章节说明,一个名称为Main的函数,是一个特殊的方法,代表了程序的入口点,也就是程序已开始所执行的方法,整个应用程序只能有一个命名为Main的函数,以下为此范例的Main函数:

     static void Main()
     {
         System.Console.WriteLine("Hello World");
     }

程序本身由Main这个方法开始执行,因此,所有的C#应用程序均必须含有这个名称的方法,你必须将程序一开始所要执行的程序代码放在这个函数里面,整个函数本身也是一个独立的程序代码块,用大括号创建。

C#是一种区分大小写的程序语言,因此,你必须在名称的第一个字母,明确地使用大写“M”为此方法的名称,而所有的程序代码,也需要注意其大小写之间的区分,而在大部分情况下,编译器在程序编译期间,也会指出这一类的错误。

4.关键字

关键字为程序语言预先定义的保留字,每一个关键字均有其所代表的特殊意义,上述程序代码的第一行定义了名称为Main的这个方法,其前使用了两个关键字。第一个关键字为static,这个关键字指定其所定义的方法调用,不需要产生类的实例。C#是一个面向对象的语言,所有方法均必须写在类里,并且通过所产生的类实例对象所调用。static提供一种类似过程式语言的公共类成员的功能,你不需要产生类实例对象,便能够直接执行其中的方法,而由于Main是程序一开始执行的地方,此时还没有任何的对象被创建。因此,Main总是被声明为static。

第二个关键字void则指定此方法不返回任何值,同样,若是你所设计的方法有返回值,则必须以返回值的类型声明定义这个方法。

5.输出文字的代码

最后,我们来看看方法中真正将文字输出到主控制台的程序代码,也就是以下这一行:

     System.Console.WriteLine("Hello World");

这一程序代码很简单,只是单纯地将“Hello World”欢迎信息输出到主控制台,并且以分号作为结束,C#以分号作为每一段独立程序代码表达式的分隔符,一段独立的程序代码本身允许进行某种独立的程序运算。

6.其他重要元素

这段程序代码里面,包含了几个重要的元素,列举说明如下:

System 命名空间(namespace),定义一个逻辑区域,用于分隔组织相关的类型以避免混淆,这个命名空间是.NET所提供的核心命名空间,编写.NET应用程序所需的基础核心类均在这个命名空间中。

Console这是一个类库里所默认的类,提供简单的主控制台文字输入/输出模式。

WriteLine()这是Console类提供的一个方法,这个方法将指定的信息输出到主控制台。

1.1.6 .NET Framework SDK

Microsoft.NET Framework软件开发工具包(SDK)包括开发人员编写、生成、测试和部署.NET Framework应用程序时所需要的一切,如帮助文档、示例以及命令行工具(如程序集连接器和强名称工具)和编译器(如C#编译器CSC.exe和VB.NET编译器VBC.exe)等。

1.1.7 程序的编译及执行

以第1.1.5节的HelloWorld程序为例,介绍程序的编译及执行。

在Windows的“开始”菜单上,选择“所有程序”→“Microsoft Visual Studio 2005”→“Visual Studio Tools”→“Visual Studio 2005命令提示”。随后会打开一个命令窗口,并且已经配置好了环境变量PATH、LIB和INCLUDE,以包括各个.NET Framework库及实用程序。

提示:

在一个普通的命令提示窗口中运行时,如果想配置环境变量,也可以直接运行“vsvars32.bat”,它位于C:\Program File\Microsoft Visual Studio 8\ Common7\Tools文件夹。

在Visual Studio 2005命令提示窗口中,输入以下命令:

     csc /out:HelloWorld.exe C:\HelloWorld.cs

该命令将根据C#源文件HelloWorld.cs来创建可执行程序HelloWorld.exe。其中“/out”参数指定生成的可执行文件的名称,此处为“HelloWorld.exe”。如果不指定“/out”参数,则生成的可执行文件名称将与源代码文件的名称相同。“C:\HelloWorld.cs”为源代码文件的绝对路径。

图1.2 编译HelloWorld

输入以下命令来执行程序,运行结果如图1.3所示。

     HelloWorld

图1.3 运行HelloWorld

1.1.8 元数据

元数据是一种二进制信息,用于对存储在公共语言运行库可移植可执行文件(PE)或存储在内存中的程序进行描述。将第1.1.7 节中的代码编译为可执行文件(PE)时,便会将元数据插入到该文件的一部分中,而将代码转换为微软中间语言(MSIL),并将其插入到该文件的另一部分中。在模块或程序集中定义和引用的每个类型和成员都将在元数据中进行说明。当执行代码时,运行库将元数据加载到内存中,并引用它来发现有关代码的类、成员、继承等信息。

元数据以非特定语言的方式描述在代码中定义的每一类型和成员。元数据存储以下信息:

程序集的说明。

标识(名称、版本、区域性、公钥)。

导出的类型。

该程序集所依赖的其他程序集。

运行所需的安全权限。

类型的说明。

名称、可见性、基类和实现的接口。

成员(方法、字段、属性、事件、嵌套的类型)。

属性。

修饰类型和成员的其他说明性元素。

对于一种更简单的编程模型来说,元数据是关键,该模型不再需要接口定义语言(IDL)文件、头文件或任何外部组件引用方法。元数据允许.NET语言自动以非特定语言的方式对其自身进行描述,而这是开发人员和用户都无法看见的。另外,通过使用属性,可以对元数据进行扩展。元数据具有以下主要优点:

自描述文件。

公共语言运行库模块和程序集是自描述的。模块的元数据包含与另一个模块进行交互所需的全部信息。元数据自动提供COM中IDL的功能,允许将一个文件同时用于定义和实现。运行库模块和程序集甚至不需要向操作系统注册。结果,运行库使用的说明始终反映编译文件中的实际代码,从而提高应用程序的可靠性。

语言互用性和更简单的基于组件的设计。

元数据提供所有必需的有关已编译代码的信息,以供你从用不同语言编写的PE文件中继承类。你可以创建用任何托管语言(任何面向公共语言运行库的语言)编写的任何类的实例,而不用担心显式封送处理或使用自定义的互用代码。

1.1.9 程序集

在第1.1.7一节中,编译后生成的“HelloWorld.exe”实际上是一个程序集。程序集是一个或多个类型定义文件及资源文件的集合。在程序集的所有文件中,有一个“清单”。清单中记录了程序集所包含的所有文件的名称。此外,还描述了程序集的版本、语言文化、发布者等。

公共语言运行库(CLR)操作的是程序集。在大多数情况下,程序集只由一个文件构成,就像前面的HelloWorld.exe那样。然而,程序集还可以由多个文件构成:一些文件是可移植执行(PE)文件、另一些文件是资源文件,比如.gif或.jpg文件。为了方便理解,可以将程序集视为一个逻辑EXE或者一个DLL文件。

可以肯定,许多人都不明白为什么微软要引入这种新的“程序集”概念。因为程序集允许我们分离可重用类型的逻辑与物理表示。例如,一个程序集可能由多个类型构成。可以将常用的类型放在一个文件中,将不常用的类型放在另一个文件中。如果采取从网上下载的方式来部署程序集,对于包含不常用类型的那个文件来说,假如客户端永远不使用那些类型,那么该文件就永远不会下载到客户端。

程序集是.NET Framework编程的基本组成部分。它是一个功能集合,并以单个实现单元(一个或多个文件)的形式生成、版本化和部署。程序集执行以下功能:

包含公共语言运行库执行的代码。如果可移植可执行(PE)文件没有相关联的程序集清单,则将不执行该文件中的微软中间语言(MSIL)代码。请注意,每个程序集只能有一个入口点(即DllMain、WinMain或Main)。

程序集形成安全边界。程序集就是在其中请求和授予权限的单元。

程序集形成类型边界。每一类型的标识均包括该类型所驻留的程序集的名称。

程序集形成引用范围边界。程序集的清单包含用于解析类型和满足资源请求的程序集元数据。它指定在该程序集之外公开的类型和资源。该清单还枚举它所依赖的其他程序集。

程序集形成版本边界。程序集是公共语言运行库中最小的可版本化单元,同一程序集中的所有类型和资源均会被版本化为一个单元。程序集的清单描述你为任何依赖项程序集所指定的版本依赖性。

程序集形成部署单元。当一个应用程序启动时,只有该应用程序最初调用的程序集必须存在。其他程序集(例如本地化资源和包含实用工具类的程序集)可以按需检索。这就使应用程序在第一次下载时保持精简。

程序集是支持并行执行的单元。

程序集可以是静态的或动态的。静态程序集可以包括.NET Framework类型(接口和类),以及该程序集的资源(位图、JPEG文件、资源文件等)。静态程序集存储在磁盘上的可移植可执行(PE)文件中。你还可以使用.NET Framework来创建动态程序集,动态程序集直接从内存运行并且在执行前不存储到磁盘上。你可以在执行动态程序集后将它们保存在磁盘上。

通常,静态程序集可能由以下四个元素组成:

● 程序集清单,包含程序集元数据。

● 类型元数据。

● 实现这些类型的微软中间语言(MSIL)代码。

● 资源集。

只有程序集清单是必需的,但也需要类型或资源来向程序集提供任何有意义的功能。

程序集通过其清单(每个程序集不可缺少的部分)进行自我描述。清单可以建立程序集标识(以文本名称的形式)、版本、区域性和数字签名(如果程序集将在应用程序间共享)。