每个程序集采用四部(four-part)名字,作为唯一的标识。这四部名字由名称、文化、开发人员以及组件版本构成。这些名字被存放于程序集自身的程序集清单(assembly manifest)中,以及引用它的所有程序集的程序集清单中。在加载时,CLR使用四部程序集名字,找到正确的组件。CLR提供System.Reflection.AssemblyName类型,便于开发人员对程序集名字进行可编程地访问,具体则是调用该类型的System.Reflection.Assembly.GetName方法。
程序集名字的Name属性往往与程序集清单的底层文件名(不包含任何文件扩展名,尽管它们可能有用)相对应。这是程序集名字中唯一的不可任选的部分。对于简单的情形,CLR在加载时只需要Name属性就能够定位正确的组件。当构建(build)程序集时,名字的这个部分是由编译器根据目标文件名自动选择的。
所有的程序集名字都有一个四部分版本号,其形式为Major.Minor.Build.Revision(主版本.次版本.内部版本号(构建版本号).修订号。例如,版本 1.5.1254.0 中的 1 表示主版本,5 表示次版本,1254 表示内部版本号,而 0 则表示修订号)。如果你没有显式地设置这个版本号,默认值将是0.0.0.0。版本号是在程序构建时设置的,比较典型的方式就是在源代码中使用定制特性。System.Reflection.AssemblyVersion特性能够接受各种的字符串格式,如表2.3所示。当你指定版本号时,Major版本号是必须的。任何缺省部分被假定为零。在构建时(build time),如果Revision部分被指定为*(星号),那么,编译器将利用时钟的时间,为每次编译生成一个单调递增的修订版本号。如果Build号被指定为*,那么,发射(emit)到程序集清单的Build号,是基于2000年2月1日起的天数,确保每一天程序集都有自己的唯一的构建号。不过,给定的构建号将只能适用于给定的24小时制。你不能将版本号的Major或Minor部分指定为*。稍后,本章将讨论程序集加载器和解析器如何使用程序集的版本。
表2.3 AssemblyVersion特性
特性参数 |
实际值 |
1 |
1.0.0.0 |
1.2 |
1.2.0.0 |
1.2.3 |
1.2.3.0 |
1.2.3.4 |
1.2.3.4 |
1.2.* |
1.2.d.s |
1.2.3.* |
1.2.3.s |
无参数 |
0.0.0.0 |
* 这里,d是指从2000年2月1日以来的天数,s是从子夜以来的秒数除以2所得的值(如果将AssemblyVersion特性设为1.0.*,那么,在2003年10月10日上午9:00生成的程序集,它的版本号为.ver 1.0.1378.16200。)
程序集名字能够包含CultureInfo特性,它能够标识组件开发所用到的语言和国家代码,也就是组件应用的语言环境。开发人员通过System.Reflection.AssemblyCulture特性指定CultureInfo。这是Internet工程任务组[Internet Engineering Task Force(IETF)]发布的1766号请求注释[Request for Comments (RFC) ]所规定的两部分字符串,即字符串的第一部分使用两个小写字母标识语言,第二(可选择)部分使用两个大写字符标识地理区域。例如,字符串”en-US”标识为美国英语。含有CultureInfo特性的程序集不能包括代码;准确地说,它们必须是纯资源(resource-only)的程序集[也称为辅助(satellite)程序集],只能包含区域化的字符串(localized string)和用户界面元素。对于包含代码的单个DLL,辅助程序集允许它们根据被部署的区域有选择地加载(和下载)相应的区域化资源。包含代码的程序集(也可以说是绝大多数程序集)被认为是文化无关的(culture-neutral),因而也就没有文化标识符。
最后,程序集名字包含一个公钥(public key),它可以标识组件的开发人员。一个程序集引用既可以使用完全的128字节的公钥,也可以使用8字节的公钥标记。公钥(或者公钥标记)被用作处理组织间的文件名冲突。例如,在内存中和磁盘上可能存在多个utilities.dll组件,它们来自不同的组织,每个组件都被确保拥有唯一的公钥。下一节我们将更详细地讨论公钥管理。
由于有时必须手工引用程序集(例如,在配置文件中使用),因此,CLR定义了一个标准格式,用于将程序集的四部名字编写为字符串。这个格式被称为程序集的显示名字(display name)。程序集的显示名字总是以程序集的简单Name开始,接着是以逗号为分隔符的属性列表,分别与程序集名字的其它三个属性相对应,并且是可选的。如果四部名字完全被指定,对应的程序集引用被称为完全限定引用(fully qualified reference)。如果缺省一个或者更多的属性,则对应的程序集引用被称为部分限定引用(partially qualified reference)。
图2.5展示了一个显示名字,以及用来控制每个属性的对应的CLR特性。注意,如果期望程序集没有文化限制,那么,显示名字必须使用Culture=neutral给予标明。同样,如果期望程序集不带公钥,显示名字也必须通过PublicKeyToken=null标明。这两种情形与不带Culture或PublicKeyToken属性的显示名字绝然不同。简单省略显示名字的某些属性,将导致生成一个部分限定名字,它允许匹配任何Culture或PublicKeyToken。
图2.5:完全限定的程序集名
一般来说,应该避免使用部分限定程序集名字;否则,CLR的许多部分将以非预期的(甚至令人不满意的)方式工作。然而,为了处理忽略该警告的代码,CLR允许在配置文件中,将部分程序集名字进行完全限定。例如,考虑下面的应用程序配置文件:
<configuration>
<runtime>
<asm:assemblyBinding xmlns:asm="urn:schemas-microsoft-com:asm.v1" >
<asm:qualifyAssembly partialName="AcmeCorp.Code"
fullName="AcmeCorp.Code,version=1.0.0.0,
publicKeyToken=a1690a5ea44bab32,culture=neutral"
/>
</asm:assemblyBinding>
</runtime>
这个配置允许下列对Assembly.Load的调用:
Assembly assm = Assembly.Load("AcmeCorp.Code");
前面的调用与下面的调用一样:
Assembly assm = Assembly.Load("AcmeCorp.Code,"+
"version=1.0.0.0,publicKeyToken=a1690a5ea44bab32,"+
"culture=neutral");
PartialName特性必须与Assembly.Load的参数完全匹配;也就是说,每个在对Assembly.Load调用中指定的属性,也必须存在于配置文件的PartialName特性中。并且,在PartialName特性中指定的每个属性,也必须在对Assembly.Load的调用中出现。稍后,本章将讨论如何定位配置文件。