如果您是组件开发人员,无论组件采用哪种语言,均可由任何 .NET Framework 应用程序访问。
|
|
|---|
|
跨语言互操作性。 |
ECMA-335 标准:公共语言基础结构的第 I 部分的第 7 条至第 11 条中进行了定义。
CLSCompliantAttribute 特性。
本文内容:
ECMA-335 标准:公共语言基础结构的第 I 部分的第 11 条。
|
|
|---|
|
但请注意,一些适用于扩展程序的规则也适用于使用 Reflection.Emit 创建的程序集。 |
您的私有实现不必符合规范。
|
|
|---|
|
CLS 遵从性的规则仅适用于组件的公共接口,而非其私有实现。 |
Age 属性,因此以下代码显示编译器警告。
using System;
[assembly: CLSCompliant(true)]
public class Person
{
private UInt16 personAge = 0;
public UInt16 Age
{ get { return personAge; } }
}
// The attempt to compile the example displays the following compiler warning:
// Public1.cs(10,18): warning CS3003: Type of 'Person.Age' is not CLS-compliant
personAge 字段的类型。
库的公共接口包括:
-
公共类的定义。
-
公共类中公共成员的定义,以及派生类可以访问的成员(即受保护的成员)的定义。
-
公共类中公共方法的参数和返回类型,以及派生类可以访问的方法的参数和返回类型。
有关这些规则的详细信息,请参阅以下各节。
|
类别 |
请参见 |
规则 |
规则编号 |
|---|---|---|---|
|
可访问性 |
family。 |
10 |
|
|
可访问性 |
例如,一个在其程序集外部可见的成员签名中出现的实例化泛型类型不应具有其类型仅在程序集内可见的泛型实参。 |
12 |
|
|
数组 |
当重载基于两个或更多数组类型时,元素类型应为命名类型。 |
16 |
|
|
特性 |
System.Attribute 类型或从该类型继承的类型。 |
41 |
|
|
特性 |
System.Double 以及基于符合 CLS 的基整数类型的任何枚举类型。 |
34 |
|
|
特性 |
modopt,请参阅第 II 部分)。 |
35 |
|
|
构造函数 |
在访问继承的实例数据之前,对象构造函数应调用其基类的某个实例构造函数。(这不适用于不需要构造函数的值类型。) |
21 |
|
|
构造函数 |
对象构造函数只能在创建对象的过程中调用,并且不应将对象初始化两次。 |
22 |
|
|
枚举 |
RTSpecialName。 |
7 |
|
|
枚举 |
enum 的值不仅限于指定的值。 |
8 |
|
|
枚举 |
枚举的文本静态字段需具有枚举本身的类型。 |
9 |
|
|
事件 |
SpecialName。 |
29 |
|
|
事件 |
事件及其访问器的可访问性应相同。 |
30 |
|
|
事件 |
remove 方法应同时存在或不存在。 |
31 |
|
|
事件 |
System.Delegate。 |
32 |
|
|
事件 |
SpecialName 特性应在适当的名称比较中被忽略,且应遵循标识符规则。 |
33 |
|
|
异常 |
但是,阻止其他类型的异常的传播无需符合 CLS 的方法。 |
40 |
|
|
常规 |
CLS 规则仅适用于类型中在定义程序集之外可访问或可显示的部分。 |
1 |
|
|
常规 |
不应将不符合 CLS 的类型的成员标记为符合 CLS。 |
2 |
|
|
泛型 |
嵌套类型中的泛型参数在位置上与其封闭类型中的泛型参数对应。 |
42 |
|
|
泛型 |
根据上面定义的规则,泛型类型的名称将对非嵌套类型上声明的或新引入到类型(如果嵌套)中的类型参数的数量进行编码。 |
43 |
|
|
泛型 |
泛型类型应该重新声明足够多的约束,以确保对基类型或接口的任何约束能够满足泛型类型约束的需要。 |
4444 |
|
|
泛型 |
用作对泛型参数的约束的类型本身应符合 CLS。 |
45 |
|
|
泛型 |
作出以下假定:CLS 规则 12 的可见性和可访问性仍适用。 |
46 |
|
|
泛型 |
对于每个抽象或虚拟泛型方法,应该有默认的具体(非抽象)实现。 |
47 |
|
|
接口 |
符合 CLS 的接口不需要不符合 CLS 的方法的定义即可实现这些方法。 |
18 |
|
|
接口 |
符合 CLS 的接口不应定义静态方法,也不应定义字段。 |
19 |
|
|
成员 |
全局静态字段和方法不符合 CLS。 |
36 |
|
|
成员 |
-- |
enum)完全相同的字段初始化元数据中指定值。 |
13 |
|
成员 |
vararg 约束不属于 CLS,并且 CLS 支持的唯一调用约定是标准托管调用约定。 |
15 |
|
|
命名约定 |
但是,若要重写继承的定义,CLI 需要对使用的原始声明进行准确编码。 |
4 |
|
|
重载 |
也就是说,CTS 允许单个类型对方法和字段使用相同的名称,但 CLS 不允许。 |
5 |
|
|
重载 |
(标识符比较后)具有相同名称的方法、属性和事件应在除返回类型不同之外还具有其他差异,CLS 规则 39 中指定的差异除外。 |
6 |
|
|
重载 |
只可重载属性和方法。 |
37 |
|
|
重载 |
op_Explicit 的转换运算符除外,这两种转换运算符也可基于其返回类型进行重载。 |
38 |
|
|
重载 |
-- |
如果类型中声明的两种或更多符合 CLS 的方法都具有相同的名称,并且对于特定的类型实例化集而言,它们具有相同的参数和返回类型,则所有这些方法在这些类型实例化时都应在语义上保持等效。 |
48 |
|
类型 |
任何其他符合 CLS 的类应从符合 CLS 的类继承。 |
23 |
|
|
属性 |
SpecialName。 |
24 |
|
|
属性 |
属性的访问器必须同为静态、同为虚拟或同为实例。 |
26 |
|
|
属性 |
所有这些类型都应该符合 CLS,并且不应是托管指针(也就是说,不应该被引用传递)。 |
27 |
|
|
属性 |
属性应具有 getter 和/或 setter 方法。 |
28 |
|
|
类型转换 |
op_Explicit,则必须提供实现强制转换的替代方法。 |
39 |
|
|
类型 |
装箱的值类型不符合 CLS。 |
3 |
|
|
类型 |
构成实例化泛型类型的所有类型应符合 CLS。 |
11 |
|
|
类型 |
类型化的引用是不符合 CLS 的。 |
14 |
|
|
类型 |
非托管的指针类型不符合 CLS。 |
17 |
|
|
类型 |
符合 CLS 的类、值类型和接口不应要求实现不符合 CLS 的成员。 |
20 |
类型和类型成员签名
对于要符合 CLS 的派生类型,其基本类型也必须符合 CLS。
NonZeroCounter 也不符合 CLS。
using System;
[assembly: CLSCompliant(true)]
[CLSCompliant(false)]
public class Counter
{
UInt32 ctr;
public Counter()
{
ctr = 0;
}
protected Counter(UInt32 ctr)
{
this.ctr = ctr;
}
public override string ToString()
{
return String.Format("{0}). ", ctr);
}
public UInt32 Value
{
get { return ctr; }
}
public void Increment()
{
ctr += (uint) 1;
}
}
public class NonZeroCounter : Counter
{
public NonZeroCounter(int startIndex) : this((uint) startIndex)
{
}
private NonZeroCounter(UInt32 startIndex) : base(startIndex)
{
}
}
// Compilation produces a compiler warning like the following:
// Type3.cs(37,14): warning CS3009: 'NonZeroCounter': base type 'Counter' is not
// CLS-compliant
// Type3.cs(7,14): (Location of symbol related to previous warning)
此外,对于泛型类型:
-
构成实例化泛型类型的所有类型必须符合 CLS。
-
所有用作针对泛型参数的约束的类型必须符合 CLS。
在这些内部类型中,下表中所列的类型都符合 CLS。
|
符合 CLS 的类型 |
说明 |
|---|---|
|
8 位无符号整数 |
|
|
16 位带符号整数 |
|
|
32 位带符号整数 |
|
|
64 位带符号整数 |
|
|
单精度浮点值 |
|
|
双精度浮点值 |
|
|
false 值类型 |
|
|
UTF 16 编码单元 |
|
|
非浮点十进制数字 |
|
|
平台定义的大小的指针或句柄 |
|
|
Char 对象的集合 |
下表中所列的内部类型不符合 CLS。
|
不符合类型 |
说明 |
符合 CLS 的替代方法 |
|---|---|---|
|
8 位带符号整数数据类型 |
||
|
指向对象及其运行时类型的指针 |
无 |
|
|
16 位无符号整数 |
||
|
32 位无符号整数 |
||
|
64 位无符号整数 |
Double |
|
|
未签名的指针或句柄 |
.NET Framework 类库或任何其他类库可能包含不符合 CLS 的其他类型;例如:
-
int* 是一个装箱的值类型,因此编译器将其标记为不符合 CLS。
using System; [assembly:CLSCompliant(true)] public unsafe class TestClass { private int* val; public TestClass(int number) { val = (int*) number; } public int* Value { get { return val; } } } // The compiler generates the following output when compiling this example: // warning CS3003: Type of 'TestClass.Value' is not CLS-compliant -
TypedReference 类显示在 .NET Framework 中。
CLSCompliantAttribute 特性部分。
您尝试编译此示例时会收到四个编译器警告。
using System;
[assembly: CLSCompliant(true)]
public class InvoiceItem
{
private uint invId = 0;
private uint itemId = 0;
private Nullable<uint> qty;
public InvoiceItem(uint sku, Nullable<uint> quantity)
{
itemId = sku;
qty = quantity;
}
public Nullable<uint> Quantity
{
get { return qty; }
set { qty = value; }
}
public uint InvoiceId
{
get { return invId; }
set { invId = value; }
}
}
// The attempt to compile the example displays the following output:
// Type1.cs(13,23): warning CS3001: Argument type 'uint' is not CLS-compliant
// Type1.cs(13,33): warning CS3001: Argument type 'uint?' is not CLS-compliant
// Type1.cs(19,26): warning CS3003: Type of 'InvoiceItem.Quantity' is not CLS-compliant
// Type1.cs(25,16): warning CS3003: Type of 'InvoiceItem.InvoiceId' is not CLS-compliant
InvoiceItem 公共接口中不符合 CLS 的类型替换为符合 CLS 的类型:
using System;
[assembly: CLSCompliant(true)]
public class InvoiceItem
{
private uint invId = 0;
private uint itemId = 0;
private Nullable<int> qty;
public InvoiceItem(int sku, Nullable<int> quantity)
{
if (sku <= 0)
throw new ArgumentOutOfRangeException("The item number is zero or negative.");
itemId = (uint) sku;
qty = quantity;
}
public Nullable<int> Quantity
{
get { return qty; }
set { qty = value; }
}
public int InvoiceId
{
get { return (int) invId; }
set {
if (value <= 0)
throw new ArgumentOutOfRangeException("The invoice number is zero or negative.");
invId = (uint) value; }
}
}
下面的示例将生成一个编译器警告,因为它使用指向整数的指针来创建整数数组。
using System;
[assembly: CLSCompliant(true)]
public class ArrayHelper
{
unsafe public static Array CreateInstance(Type type, int* ptr, int items)
{
Array arr = Array.CreateInstance(type, items);
int* addr = ptr;
for (int ctr = 0; ctr < items; ctr++) {
int value = *addr;
arr.SetValue(value, ctr);
addr++;
}
return arr;
}
}
// The attempt to compile this example displays the following output:
// UnmanagedPtr1.cs(8,57): warning CS3001: Argument type 'int*' is not CLS-compliant
abstract 的类),该类的所有成员也必须符合 CLS。
命名约定
由于它们只是大小写不同,因此 C# 编译器会将其标记为不符合 CLS。
using System;
[assembly: CLSCompliant(true)]
public class Person : person
{
}
public class person
{
}
// Compilation produces a compiler warning like the following:
// Naming1.cs(11,14): warning CS3005: Identifier 'person' differing
// only in case is not CLS-compliant
// Naming1.cs(6,14): (Location of symbol related to previous warning)
这表示:
-
System.Globalization.UnicodeCategory枚举。
-
后继字符可以作为第一个字符来自任何类别,还可以包含无间隔标记、间距组合标记、十进制数字、连接器标点符号以及格式设置代码。
C# 和 Visual Basic 编译器都将源代码标记为不符合 CLS。
public class Size
{
private double a1;
private double a2;
public double Å
{
get { return a1; }
set { a1 = value; }
}
public double Å
{
get { return a2; }
set { a2 = value; }
}
}
// Compilation produces a compiler warning like the following:
// Naming2a.cs(16,18): warning CS3005: Identifier 'Size.Å' differing only in case is not
// CLS-compliant
// Naming2a.cs(10,18): (Location of symbol related to previous warning)
// Naming2a.cs(18,8): warning CS3005: Identifier 'Size.Å.get' differing only in case is not
// CLS-compliant
// Naming2a.cs(12,8): (Location of symbol related to previous warning)
// Naming2a.cs(19,8): warning CS3005: Identifier 'Size.Å.set' differing only in case is not
// CLS-compliant
// Naming2a.cs(13,8): (Location of symbol related to previous warning)
具体而言,对于类型成员:
-
字段和嵌套类型只能通过名称区分。
-
具有相同名称的方法、属性和事件必须具有除返回类型不同之外的其他不同之处。
Conversion 属性也违反了此要求。
using System;
[assembly: CLSCompliant(true)]
public class Converter
{
public double Conversion(int number)
{
return (double) number;
}
public float Conversion(int number)
{
return (float) number;
}
public double Conversion(long number)
{
return (double) number;
}
public bool Conversion
{
get { return true; }
}
}
// Compilation produces a compiler error like the following:
// Naming3.cs(13,17): error CS0111: Type 'Converter' already defines a member called
// 'Conversion' with the same parameter types
// Naming3.cs(8,18): (Location of symbol related to previous error)
// Naming3.cs(23,16): error CS0102: The type 'Converter' already contains a definition for
// 'Conversion'
// Naming3.cs(8,18): (Location of symbol related to previous error)
否则,该示例将生成错误消息“关键字无法用作标识符”,并且编译将失败。
Public Class [case]
Private _id As Guid
Private name As String
Public Sub New(name As String)
_id = Guid.NewGuid()
Me.name = name
End Sub
Public ReadOnly Property ClientName As String
Get
Return name
End Get
End Property
End Class
如果没有该符号,C# 编译器会显示两条错误消息:“应为类型”和“无效表达式术语‘case’”。
using System;
public class Example
{
public static void Main()
{
@case c = new @case("John");
Console.WriteLine(c.ClientName);
}
}
类型转换
公共语言规范定义了两个转换运算符:
-
Decimal 值。
-
Char。
Xxx 方法。
FromSingle 方法定义为显式转换运算符的替代方法。
using System;
public struct UDouble
{
private double number;
public UDouble(double value)
{
if (value < 0)
throw new InvalidCastException("A negative value cannot be converted to a UDouble.");
number = value;
}
public UDouble(float value)
{
if (value < 0)
throw new InvalidCastException("A negative value cannot be converted to a UDouble.");
number = value;
}
public static readonly UDouble MinValue = (UDouble) 0.0;
public static readonly UDouble MaxValue = (UDouble) Double.MaxValue;
public static explicit operator Double(UDouble value)
{
return value.number;
}
public static implicit operator Single(UDouble value)
{
if (value.number > (double) Single.MaxValue)
throw new InvalidCastException("A UDouble value is out of range of the Single type.");
return (float) value.number;
}
public static explicit operator UDouble(double value)
{
if (value < 0)
throw new InvalidCastException("A negative value cannot be converted to a UDouble.");
return new UDouble(value);
}
public static implicit operator UDouble(float value)
{
if (value < 0)
throw new InvalidCastException("A negative value cannot be converted to a UDouble.");
return new UDouble(value);
}
public static Double ToDouble(UDouble value)
{
return (Double) value;
}
public static float ToSingle(UDouble value)
{
return (float) value;
}
public static UDouble FromDouble(double value)
{
return new UDouble(value);
}
public static UDouble FromSingle(float value)
{
return new UDouble(value);
}
}
数组
符合 CLS 的数组符合以下规则:
-
Numbers.GetTenPrimes 方法返回的数组是否符合 CLS。
1 [assembly: CLSCompliant(true)] 2 3 public class Numbers 4 { 5 public static Array GetTenPrimes() 6 { 7 Array arr = Array.CreateInstance(typeof(Int32), new int[] {10}, new int[] {1}); 8 arr.SetValue(1, 1); 9 arr.SetValue(2, 2); 10 arr.SetValue(3, 3); 11 arr.SetValue(5, 4); 12 arr.SetValue(7, 5); 13 arr.SetValue(11, 6); 14 arr.SetValue(13, 7); 15 arr.SetValue(17, 8); 16 arr.SetValue(19, 9); 17 arr.SetValue(23, 10); 18 19 return arr; 20 } 21 }
-
UInt32 类型而将其标识为不合规,但无法识别第二个包含不符合 CLS 元素的数组。
1 using System; 2 3 [assembly: CLSCompliant(true)] 4 5 public class Numbers 6 { 7 public static UInt32[] GetTenPrimes() 8 { 9 uint[] arr = { 1u, 2u, 3u, 5u, 7u, 11u, 13u, 17u, 19u }; 10 return arr; 11 } 12 13 public static Object[] GetFivePrimes() 14 { 15 Object[] arr = { 1, 2, 3, 5u, 7u }; 16 return arr; 17 } 18 } 19 // Compilation produces a compiler warning like the following: 20 // Array2.cs(8,27): warning CS3002: Return type of 'Numbers.GetTenPrimes()' is not 21 // CLS-compliant
-
GetSquares 方法的定义符合 CLS。
using System; using System.Numerics; [assembly: CLSCompliant(true)] public class Numbers { public static byte[] GetSquares(byte[] numbers) { byte[] numbersOut = new byte[numbers.Length]; for (int ctr = 0; ctr < numbers.Length; ctr++) { int square = ((int) numbers[ctr]) * ((int) numbers[ctr]); if (square <= Byte.MaxValue) numbersOut[ctr] = (byte) square; // If there's an overflow, assign MaxValue to the corresponding // element. else numbersOut[ctr] = Byte.MaxValue; } return numbersOut; } public static BigInteger[] GetSquares(BigInteger[] numbers) { BigInteger[] numbersOut = new BigInteger[numbers.Length]; for (int ctr = 0; ctr < numbers.Length; ctr++) numbersOut[ctr] = numbers[ctr] * numbers[ctr]; return numbersOut; } }
接口
符合 CLS 的接口不能有:
-
如果您在接口中定义静态成员,那么 C# 和 Visual Basic 编译器将生成编译器错误。
-
如果您在接口中定义字段,则 C# 和 Visual Basic 编译器将生成编译器错误。
-
此示例生成编译器警告。
using System; [assembly:CLSCompliant(true)] public interface INumber { int Length(); [CLSCompliant(false)] ulong GetUnsigned(); } // Attempting to compile the example displays output like the following: // Interface2.cs(8,32): warning CS3010: 'INumber.GetUnsigned()': CLS-compliant interfaces // must have only CLS-compliant members如果一个符合 CLS 的框架公开实现不符合 CLS 接口的类,则其还应提供所有不符合 CLS 的成员的具体实现。
Temperature 类来说明此方案。
using System;
[assembly: CLSCompliant(true)]
public interface IFahrenheit
{
decimal GetTemperature();
}
public interface ICelsius
{
decimal GetTemperature();
}
public class Temperature : ICelsius, IFahrenheit
{
private decimal _value;
public Temperature(decimal value)
{
// We assume that this is the Celsius value.
_value = value;
}
decimal IFahrenheit.GetTemperature()
{
return _value * 9 / 5 + 32;
}
decimal ICelsius.GetTemperature()
{
return _value;
}
}
public class Example
{
public static void Main()
{
Temperature temp = new Temperature(100.0m);
ICelsius cTemp = temp;
IFahrenheit fTemp = temp;
Console.WriteLine("Temperature in Celsius: {0} degrees",
cTemp.GetTemperature());
Console.WriteLine("Temperature in Fahrenheit: {0} degrees",
fTemp.GetTemperature());
}
}
// The example displays the following output:
// Temperature in Celsius: 100.0 degrees
// Temperature in Fahrenheit: 212.0 degrees
枚举
符合 CLS 的枚举必须遵循下列规则:
-
UInt32 的枚举并生成编译器警告。
1 using System; 2 3 [assembly: CLSCompliant(true)] 4 5 public enum Size : uint { 6 Unspecified = 0, 7 XSmall = 1, 8 Small = 2, 9 Medium = 3, 10 Large = 4, 11 XLarge = 5 12 }; 13 14 public class Clothing 15 { 16 public string Name; 17 public string Type; 18 public string Size; 19 } 20 // The attempt to compile the example displays a compiler warning like the following: 21 // Enum3.cs(6,13): warning CS3009: 'Size': base type 'uint' is not CLS-compliant
-
这使得您可以隐式引用字段值。
-
State。
-
有两种枚举:
-
System.FlagsAttribute 自定义特性表示。
-
System.FlagsAttribute 自定义特性表示。
Enum 结构的文档。
-
-