1.4.1 私有程序集
私有程序集是使程序集中最简单的类型。他们一班附带于软件上面并且也仅仅被该软件所用。一般情况下附带私有程序集的情况是这样的,你在编写一个由一个可执行文件和好几个类库组成的应用程序,而类库中的代码你只想让这个应用程序使用。
系统保证私有程序集不会被其他的软件所使用,因为应用程序只可以加载与主可执行文件在同一目录或者其子目录的私有程序集。
由于我们一般认为商业软件总是会被安装属于他自己的一个目录里,这就是说没有软件包被以外覆盖,修改或者应用程序以外加载其他软件包的程序集的可能。因此,程序集只能够被自己所对应的软件包使用,所以对于什么软件使用他们你就有更多的控制权利。因此,不需要采取安全防范措施,根本就不会出现如其他的商用软件用一些新版本覆盖你的程序集的可能(专门设计用来执行恶意破坏的软件除外)。当然,名称也没有任何冲突。如果你的私有程序集的类和其他的人的私有程序集的类有相同的名称也不要紧,因为任何一个应用程序都只能够使用自己的私有程序集。
因为一个私有程序集是完全自包含的,所以配置他们的过程是非常简单的。在部署是你只需要简单的将应用程序文件目录系统的特定目录中就可以了(不需要注册注册表项)。这个过程被称为“零影响安装“(或者xcopy安装,或者是我们说的绿色安装)。
1.4.2 共享程序集
共享程序集被规定为任何应用程序都可以使用的公共库。因为任何软件都可以访问共享程序集。需要采取一些防护措施来避免如下的风险:
? 名称冲突,其他的公司的共享程序集执行类型和你自己的共享程序集有相同的名称。由于客户机代码在理论上存在同时访问两个程序集的可能,所以这是一个严重的问题。
? 存在一个程序基本不同版本的同一个程序集重写的可能,并且新版本可能与某些已经存在的客户机代码不兼容。
解决这些问题的办法是将共享程序集放置在文件系统中一个特定的目录子树中,被称作global assembly cache (GAC)。和私有程序集不同,不可以简单的将共享程序集复制到应用程序的目录中,它需要被专门的安装到缓冲区中。这个过程可以利用许多.NET工具来完成,包括对程序集进行特定的检查,也包括在程序集缓冲区中建立一个小的目录层次结构来确保程序集的完整性。
为了消除名称冲突的可能性,共享程序集都不赋予了一个基于私有密匙加密法加密的名称(私有程序集只需要简单的指定其主文件的名称为其名称就可以了)。这个名称被称作“强名“,保证唯一,并且每个引用共享程序集的应用程序都必须提供此名称。
程序集可能被覆盖的问题通过允许同时安装两个不同版本的相同程序集的时候,在程序集清单中记录特定的版本信息来解决的,
1.4.3 反射
因为程序集中存储了元数据,包括所有的类型和这些类型的成员的所有细节都在程序集定义了,所以就可以用程序访问元数据。这其中的所有细节我们将在第10章讨论。这就是可能令人感兴趣的被称作反射的技术,它说明托管代码可以检测其他的托管代码甚至是检测自身,已确定代码的信息。反射经常被用于获得属性的详细信息,当然,你也可以将反射技术用于其它目的,例如通过以字符串的方式提供类或者方法的名字来间接实现类或者调用方法。通过这种方法你可以在运行时根据用户输入才决定需要实例化的类或者需要调用的方法,而不需在程序编译之前就决定。
1.5 .NET Framework类库
至少从一个开发者的观点来看,编写托管代码的一个最大好处就是你可以使用.NET基础类库(base class library)。
.NET基础类就是一大堆已经编写好了的托管代码类的集合,几乎所有以前可以用Windows API来完成的工作她都可以帮你完成。这些类同样也遵守IL所采用的对象模型,基于单继承的对象模型。这就是说你既可以实例化任何一个需要的.NET基础类,或者你可以从其中派生你自己的类。
.NET基础类库的一个巨大的优点就是使用起来非常方便。例如,如果要启动一个线程,你可以直接调用Thread类的Start()方法。如果要销毁一个TextBox,你需要设计TextBox对象的Enabled属性为false。虽然Visual Basic 和 Java的开发者很熟悉这种使用方便的类库,但是对于C++开发者来说这已经带来了极大的解脱,毕竟多年来他们一直在使用像GetDIBits( ), RegisterWndClassEx( ), 和 IsEqualIID( )这样的API函数,而且在其间需要传递很多的Windows handles。
另一方面,C++开发者总是可以方便的访问整个Windows API,而Visual Basic 6 和 Java开发者通过各自的语言访问操作系统的基础功能就会受到很多限制。.NET基础类库的创新就在于它将类似Visual Basic 和 Java类库使用的便利性和覆盖整个Windows API功能的全面性结合起来。当然,仍然有一些Windows的特性我们无法通过使用基础类库得到,必须使用API功能才能实现,但是,一般来说,那些使用不到的都是些特殊的特性。对于每天的应用而言,基础类库已经是足够的了。如果你确实需要调用API功能的话,不管你是在使用C#, C++, 或者 Visual Basic .NET,.NET也提供了所谓“platform- invoke“,以确保数据类型被正确的转换,这样这种调用的工作也没有在C++中直接调用函数困难。
注意:WinCV,一个基于Windows实用程序,可以用来游览基础类库中的类,结构,接口和枚举类型。我们将要在第12章讨论WinCV。
尽管从题目上看第三章是用来介绍基础类库这个主题的,但是实际上,当我们完成了C#语言的语法学习后,这本书的主要任务就是教给你如何使用.NET基础类库中的各种各样的类了。这是一个非常广泛的基础类库!作为一个大致的介绍,.NET的基础类库包括:
? IL提供的核心特性(包括,基本数据类型和CTS,具体见第3章)
? Windows GUI的支持和控制(见第19章)
? Web Forms (ASP.NET, 在第25 至 27章讨论)
? 数据访问(ADO.NET, 见第 21 和 22章)
? 目录访问(见第24章)
? 文件系统和注册表访问(见第30章)
? 网络和Web游览(见第31章)
? .NET属性和反射(见第10章)
? 访问Windows操作系统(环境变量等,见第14章)
? COM互操作性(见第28和29章)
附带说明,根据微软的源文件,.NET基础类库中的大多数代码实际上都是用C#编写的!
1.5.1 命名空间
命名空间是.NET消除类和类之间名称冲突的办法。他是用来避免如下状况的:你定义一个表示消费者的类,并且给她取名叫做Customer,而正好有另一个人也是这样做的,这样就引起了冲突(想象一下,在一个有很多消费者的商业中)。
命名空间只是一组数据类型,但是命名空间里的数据类型会自动在自己的名字前加上命名空间的名字作为前缀。而且命名空间是可以互相嵌套的。比如,大多数用于一般目的的.NET基础类都被放在一个称为System的命名空间里。基础类Array就在这个命名空间里,所以数组的全名是System.Array。
.NET要求所有的数据类型都要定义在命名空间里,例如你可以将你的Customer类放在一个叫YourCompanyName的命名空间里。这样这个类的全名就是“YourCompanyName.Customer“。
注意:如果没有明确地提供命名空间,那么定义的类型就会被添加到一个没有名字的全局命名空间里。
微软建议,对于大多情况,你应该指定一个至少两层嵌套结构的命名空间名称:第一个代指你的公司名称,第二个用来指代类所存在于的技术或者软件包的名称,例如YourCompanyName.SalesServices.Customer。这样就保证了在大多数情况下你的应用程序的类都不会和其他的组织的类发生名称冲突。
我们将要在第2章更加详细地了解命名空间。
1.6 用C#创建.NET应用程序
C#当然可以用来创建控制台应用程序,一种在DOS窗口下运行