公共语言规范
要和其他对象完全交互,而不管这些对象是以何种语言实现的,对象必须只向调用方公开那些它们必须与之互用的所有语言的通用功能。 为此定义了公共语言规范 (CLS),它是许多应用程序所需的一套基本语言功能。 CLS 规则定义了常规类型系统的子集,即所有适用于常规类型系统的规则都适用于 CLS,除非 CLS 中定义了更严格的规则。 CLS 通过定义一组开发人员可以确信在多种语言中都可用的功能来增强和确保语言互用性。 CLS 还建立了 CLS 遵从性要求,这帮助您确定您的托管代码是否符合 CLS 以及一个给定的工具对托管代码(该代码是使用 CLS 功能的)开发的支持程度。
如果您的组件在对其他代码(包括派生类)公开的 API 中只使用了 CLS 功能,那么可以保证在任何支持 CLS 的编程语言中都可以访问该组件。 遵守 CLS 规则、仅使用 CLS 中所包含功能的组件叫做符合 CLS 的组件。
按 .NET Framework Class Library(.NET Framework 类库)中的类型定义的大多数成员均符合 CLS。 但是,类库中的某些类型具有一个或多个不符合 CLS 的成员。 这些成员能够支持 CLS 中没有的语言功能。 在参考文档中以及所有存在符合 CLS 的替换选项的情况中,不符合 CLS 的类型和成员也照此标识。 有关 .NET Framework 类库中类型的更多信息,请参见 .NET Framework Class Library(.NET Framework 类库)。
CLS 在设计上足够大,可以包括开发人员经常需要的语言构造;同时也足够小,大多数语言都可以支持它。 此外,任何不可能快速验证代码类型安全性的语言构造都被排除在 CLS 之外,以便所有符合 CLS 的语言都可以生成可验证的代码(如果它们选择这样做)。 有关类型安全验证的更多信息,请参见托管执行过程。
下表总结了 CLS 中的功能并指出该功能是否“同时”适用于开发人员和编译器或仅适用于编译器。 提供此表的目的在于提供信息,但可能并不全面。 有关详细信息,请参见 Microsoft Developer Network (MSDN) 网站上的“Common Language Infrastructure, Partition I”(公共语言基础结构,第 I 部分)中介绍的规范。
功能 |
适用对象 |
说明 |
---|---|---|
常规 |
|
|
可见性 |
全部 |
CLS 规则仅适用于类型中在定义程序集之外公开的部分。 |
全局成员 |
全部 |
全局静态字段和方法不符合 CLS。 |
命名 |
|
|
字符和大小写 |
全部 |
符合 CLS 的语言编译器必须遵循 Unicode 标准 3.0 技术报告 15 的附件 7 中的规则,其中规定了可以用在标识符的开头以及包含在标识符中的字符。 此标准可以从 Unicode Consortium(Unicode 联合会)网站获取。 要让两个标识符被认为是不同的,它们要在除大小写不同之外尚有其他不同之处。 |
关键字 |
编译器 |
符合 CLS 的语言编译器提供用于引用与关键字相符的标识符的机制。 符合 CLS 的语言编译器提供定义和用名称(该名称是语言中的关键字)重写虚方法的机制。 |
唯一性 |
全部 |
除了通过重载来解析的名称可以相同之外,符合 CLS 的范围中的所有名称都必须是不同的,即使在这些名称用于两种不同类型的成员时也应如此。 例如,CLS 不允许一个类型对方法和字段使用相同的名称。 |
签名 |
全部 |
所有出现在类型或成员签名中的返回类型和参数类型都必须是符合 CLS 的。 |
类型 |
|
|
基元类型 |
全部 |
.NET Framework 类库包括与编译器使用的基元数据类型相对应的类型。 在这些类型中,下列类型符合 CLS:Byte、Int16、Int32、Int64、Single、Double、Boolean、Char、Decimal、IntPtr 和 String。 有关这些类型的更多信息,请参见 .NET Framework Class Library(.NET Framework 类库)中的类型表。 |
已装箱的类型 |
全部 |
已装箱的值类型(已转换为对象的值类型)不属于 CLS。 在需要时,转而使用 System.Object、System.ValueType 或 System.Enum。 |
可见性 |
全部 |
类型和成员声明不能包含比所声明的类型或成员可见性或可访问性差的类型。 |
接口方法 |
编译器 |
当单个类型实现两个接口,而每个接口都需要有具有相同名称和签名的方法定义时,符合 CLS 的语言编译器必须具有用于以上情况的语法。 这些方法必须被视为是独特的,并且不需要相同的实现。 |
闭包 |
全部 |
符合 CLS 的接口和抽象类中的单个成员必须都定义成是符合 CLS 的。 |
构造函数调用 |
全部 |
在构造函数访问任何继承的实例数据之前,它必须调用基类的构造函数。 |
类型化的引用 |
全部 |
类型化的引用是不符合 CLS 的。 (类型化的引用是一个特殊的构造,它包含一个对对象的引用和一个对类型的引用。 类型化的引用使公共语言运行时可以为具有可变数目参数的方法提供 C++ 样式的支持。) |
类型成员 |
|
|
重载 |
全部 |
允许重载索引属性、方法和构造函数;不能重载字段和事件。 属性不得由类型(即其 getter 方法的返回类型)重载,但允许用不同数目或类型的索引对这些属性进行重载。 方法只能基于方法的参数数目和类型以及方法的泛型参数数目(如果有泛型方法)来重载。 运算符重载不在 CLS 的范围中。 但是,CLS 提供了有关提供有用名称(例如 Add())及在元数据中设置位的指南。 要支持运算符重载的编译器应该遵循这些指南,但这不是必须的。 |
重载成员的唯一性 |
全部 |
单进行标识符比较,字段和嵌套类型就必须是不同的。 (标识符比较后)具有相同名称的方法、属性和事件必须在除返回类型不同之外具有其他不同之处。 |
转换运算符 |
全部 |
如果 op_Implicit 或 op_Explicit 其中之一在其返回类型上重载,则必须有提供转换的替代方法。 |
方法 |
|
|
重写方法的可访问性 |
全部 |
当重写继承的方法时,除非重写一个从另一个带有 FamilyOrAssembly 可访问性的程序集继承的方法,否则可访问性不能改变。 在这种情况下,重写必须具有 Family 可访问性。 |
参数列表 |
全部 |
CLS 支持的唯一调用约定就是标准托管调用约定;不允许可变长度参数列表。 (使用 Microsoft Visual Basic 中的 ParamArray 关键字和 C# 中的 params 关键字来支持可变数目的参数。) |
属性 |
|
|
访问器元数据 |
编译器 |
实现属性方法的 getter 和 setter 方法在元数据中标有 mdSpecialName 标识符。 |
修饰符 |
全部 |
属性和其访问器必须同为 static、同为 virtual 或同为 instance。 |
访问器名称 |
全部 |
属性必须遵循特定的命名方式。 对于一个名为 Name 的属性,如果定义了 getter 方法,它将叫做 get_Name;如果定义了 setter 方法,它将叫做 set_Name。 |
返回类型和参数 |
全部 |
属性的类型是 getter 的返回类型和 setter 最后一个参数的类型。 属性参数的类型是对应于 getter 的参数的类型和 setter 除最后一个参数之外所有参数的类型。 所有这些类型都必须符合 CLS,并且不能是托管指针;它们不得被引用传递。 |
事件 |
|
|
事件方法 |
全部 |
用于添加和移除事件的方法必须同时存在或同时不存在。 |
事件方法元数据 |
编译器 |
实现事件的方法在元数据中必须标有 mdSpecialName 标识符。 |
访问器可访问性 |
全部 |
用于添加、移除和引发事件的方法的可访问性必须相同。 |
修饰符 |
全部 |
用于添加、移除和引发事件的方法必须同为 static、同为 virtual 或同为 instance。 |
事件方法名称 |
全部 |
事件必须遵循特定的命名方式。 对于一个名为 MyEvent 的事件,如果定义了 add 方法,它将叫做 add_MyEvent;如果定义了 remove 方法,它将叫做 remove_MyEvent;如果定义了 raise 方法,它将叫做 raise_MyEvent。 |
参数 |
全部 |
添加和移除事件的方法必须分别取一个参数,该参数的类型定义事件的类型,并且该类型必须派生自 System.Delegate。 |
指针类型 |
|
|
指针 |
全部 |
指针类型和函数指针类型是不符合 CLS 的。 |
接口 |
|
|
成员签名 |
全部 |
符合 CLS 的接口要实现不符合 CLS 的方法,应该不需要这些方法的定义。 |
成员修饰符 |
全部 |
符合 CLS 的接口不能定义静态方法,也不能定义字段。 允许这类接口定义属性、事件和虚方法。 |
引用类型 |
|
|
构造函数调用 |
全部 |
对于引用类型,调用对象构造函数仅作为创建对象的一部分,对象只初始化一次。 |
类类型 |
|
|
继承 |
全部 |
符合 CLS 的类必须从符合 CLS 的类(System.Object 符合 CLS)继承。 |
数组1 |
|
|
元素类型 |
全部 |
数组元素必须是符合 CLS 的类型。 |
维数 |
全部 |
数组必须具有大于零的固定的维度数目。 |
范围 |
全部 |
数组的所有维数必须具有零下限。 |
枚举 |
|
|
基础类型 |
全部 |
|
FlagsAttribute |
编译器 |
枚举的定义中存在 System.FlagsAttribute 自定义特性,这指明应将该枚举视为一组位域(标志)。如果没有该特性,则指明应将该类型视为一组枚举常数。 建议语言使用 FlagsAttribute 或语言特定的语法两者之一来区分这两种类型的枚举。 |
字段成员 |
全部 |
枚举的 static 字段的类型必须和枚举本身的类型相同。 |
异常 |
|
|
继承 |
全部 |
引发的对象必须是 System.Exception 类型或从 System.Exception 继承。 |
自定义特性 |
|
|
值编码 |
编译器 |
要求符合 CLS 的编译器只处理自定义特性(元数据中自定义特性的表示形式)编码的子集。 只有下列类型才能出现在这些编码中:System.Type、System.String、System.Char、System.Boolean、System.Byte、System.Int16、System.Int32、System.Int64、System.Single、System.Double 以及任何基于符合 CLS 的基础整数类型的枚举类型。 |
元数据 |
|
|
CLS 遵从性 |
全部 |
CLS 遵从性与程序集的遵从性不同的类型(这些类型是在该程序集中定义的)都必须标有此 System.CLSCompliantAttribute。 同样,其 CLS 遵从性与其类型的遵从性不同的所有成员也必须进行标记。 如果某个成员或类型被标记为不符合 CLS,则必须提供一个符合 CLS 的替换选项。 |
泛型 |
||
类型名称 |
编译器 |
泛型类型的名称必须对类型上声明的类型参数的数目进行编码。 嵌套泛型类型的名称必须对新引入到类型中的类型参数的数目进行编码。 |
嵌套类型 |
编译器 |
嵌套类型拥有的泛型参数数目必须至少与封闭类型的一样多。 嵌套类型中的泛型参数在位置上与其封闭类型中的泛型参数对应。 |
约束 |
全部 |
泛型类型必须声明足够多的约束,以确保对基类型或接口的任何约束能够满足泛型类型约束的需要。 |
约束类型 |
全部 |
用作对泛型参数的约束的类型本身必须符合 CLS。 |
成员签名 |
全部 |
实例化泛型类型中的成员(包括嵌套类型)的可见性和可访问性被认为限制在特定的实例化,而不是限制在整个泛型类型声明中。 |
泛型方法 |
全部 |
对于每个抽象或虚拟泛型方法,必须有默认具体(非抽象)实现。 |
1. 交错数组(即数组的数组)符合 CLS。 在 .NET Framework 1.0 版中,C# 编译器错误地将其报告为不符合。