类型Types

C # 语言的类型分为两个主要类别: 值类型 _ 和 _引用类型*The types of the C# language are divided into two main categories: value types _ and _reference types*. 值类型和引用类型都可以是 *泛型类型*,它采用一个或多个 _ 类型参数 *。Both value types and reference types may be generic types, which take one or more _*type parameters**. 类型参数可以同时指定值类型和引用类型。Type parameters can designate both value types and reference types.

type
    : value_type
    | reference_type
    | type_parameter
    | type_unsafe
    ;

类型(指针)的最终类别仅在不安全代码中提供。The final category of types, pointers, is available only in unsafe code. 指针类型中对此进行了进一步讨论。This is discussed further in Pointer types.

值类型与引用类型的不同之处在于,值类型的变量直接包含其数据,而引用类型的变量存储 *引用 数据,后者称为 _ 对象 *。Value types differ from reference types in that variables of the value types directly contain their data, whereas variables of the reference types store references _ to their data, the latter being known as _objects**. 对于引用类型,两个变量可以引用同一对象,因此,对一个变量执行的运算可能会影响另一个变量所引用的对象。With reference types, it is possible for two variables to reference the same object, and thus possible for operations on one variable to affect the object referenced by the other variable. 对于值类型,每个变量都有自己的数据副本,对一个变量执行的操作不可能影响另一个。With value types, the variables each have their own copy of the data, and it is not possible for operations on one to affect the other.

C # 的类型系统是统一的,因此任何类型的值都可以被视为对象。C#'s type system is unified such that a value of any type can be treated as an object. 每种 C# 类型都直接或间接地派生自 object 类类型,而 object 是所有类型的最终基类。Every type in C# directly or indirectly derives from the object class type, and object is the ultimate base class of all types. 只需将值视为类型 object,即可将引用类型的值视为对象。Values of reference types are treated as objects simply by viewing the values as type object. 通过执行装箱和取消装箱操作 (装箱和取消 装箱) ,将值类型的值视为对象。Values of value types are treated as objects by performing boxing and unboxing operations (Boxing and unboxing).

值类型Value types

值类型是结构类型或枚举类型。A value type is either a struct type or an enumeration type. C # 提供一组称为 简单类型 的预定义结构类型。C# provides a set of predefined struct types called the simple types. 简单类型通过保留字进行标识。The simple types are identified through reserved words.

value_type
    : struct_type
    | enum_type
    ;

struct_type
    : type_name
    | simple_type
    | nullable_type
    ;

simple_type
    : numeric_type
    | 'bool'
    ;

numeric_type
    : integral_type
    | floating_point_type
    | 'decimal'
    ;

integral_type
    : 'sbyte'
    | 'byte'
    | 'short'
    | 'ushort'
    | 'int'
    | 'uint'
    | 'long'
    | 'ulong'
    | 'char'
    ;

floating_point_type
    : 'float'
    | 'double'
    ;

nullable_type
    : non_nullable_value_type '?'
    ;

non_nullable_value_type
    : type
    ;

enum_type
    : type_name
    ;

与引用类型的变量不同,值类型的变量 null 仅在值类型是可以为 null 的类型时才可包含值。Unlike a variable of a reference type, a variable of a value type can contain the value null only if the value type is a nullable type. 对于每个不可为 null 的值类型,都有一个对应的可以为 null 的值类型,用于表示相同的一组值和值 nullFor every non-nullable value type there is a corresponding nullable value type denoting the same set of values plus the value null.

对值类型的变量赋值会创建要分配的值的副本。Assignment to a variable of a value type creates a copy of the value being assigned. 这不同于对引用类型的变量的赋值,后者复制引用,而不是由引用标识的对象。This differs from assignment to a variable of a reference type, which copies the reference but not the object identified by the reference.

System.object 类型The System.ValueType type

所有值类型都隐式继承自类 System.ValueType ,而该类又从类继承 objectAll value types implicitly inherit from the class System.ValueType, which, in turn, inherits from class object. 任何类型都不能从值类型派生,因此值类型 (密封类) 隐式密封。It is not possible for any type to derive from a value type, and value types are thus implicitly sealed (Sealed classes).

请注意, System.ValueType 并不是 value_typeNote that System.ValueType is not itself a value_type. 相反,它是从其自动派生所有 value_typeclass_typeRather, it is a class_type from which all value_type s are automatically derived.

默认构造函数Default constructors

所有值类型都隐式声明称为 *默认构造函数 _ 的公共无参数实例构造函数。All value types implicitly declare a public parameterless instance constructor called the *default constructor . 默认构造函数返回一个0初始化的实例,该实例称为 " *默认值**" 作为 "值类型":The default constructor returns a zero-initialized instance known as the _ default value* for the value type:

  • 对于所有 simple_type,默认值是由所有零的位模式生成的值:For all simple_type s, the default value is the value produced by a bit pattern of all zeros:
    • 对于、、、、、、 sbyte byte short ushort int uint longulong ,默认值为 0For sbyte, byte, short, ushort, int, uint, long, and ulong, the default value is 0.
    • 对于 char ,默认值为 '\x0000'For char, the default value is '\x0000'.
    • 对于 float ,默认值为 0.0fFor float, the default value is 0.0f.
    • 对于 double ,默认值为 0.0dFor double, the default value is 0.0d.
    • 对于 decimal ,默认值为 0.0mFor decimal, the default value is 0.0m.
    • 对于 bool ,默认值为 falseFor bool, the default value is false.
  • 对于 enum_type E ,默认值为,将 0 转换为类型 EFor an enum_type E, the default value is 0, converted to the type E.
  • 对于 struct_type,默认值为通过将所有值类型字段设置为其默认值和所有引用类型字段而产生的值 nullFor a struct_type, the default value is the value produced by setting all value type fields to their default value and all reference type fields to null.
  • 对于 nullable_type 默认值为其 HasValue 属性为 false 且属性未定义的实例 ValueFor a nullable_type the default value is an instance for which the HasValue property is false and the Value property is undefined. 默认值也称为可以为 null 的类型的 null 值The default value is also known as the null value of the nullable type.

与任何其他实例构造函数一样,值类型的默认构造函数使用运算符进行调用 newLike any other instance constructor, the default constructor of a value type is invoked using the new operator. 出于效率方面的考虑,此要求实际上不会使实现生成构造函数调用。For efficiency reasons, this requirement is not intended to actually have the implementation generate a constructor call. 在下面的示例中,变量 i 和都 j 初始化为零。In the example below, variables i and j are both initialized to zero.

class A
{
    void F() {
        int i = 0;
        int j = new int();
    }
}

由于每个值类型都隐式具有一个公共的无参数实例构造函数,因此结构类型不可能包含无参数构造函数的显式声明。Because every value type implicitly has a public parameterless instance constructor, it is not possible for a struct type to contain an explicit declaration of a parameterless constructor. 但结构类型允许) (构造函数 声明参数化实例构造函数。A struct type is however permitted to declare parameterized instance constructors (Constructors).

结构类型Struct types

结构类型是一种值类型,可以声明常量、字段、方法、属性、索引器、运算符、实例构造函数、静态构造函数和嵌套类型。A struct type is a value type that can declare constants, fields, methods, properties, indexers, operators, instance constructors, static constructors, and nested types. 结构 声明中描述了结构类型的声明。The declaration of struct types is described in Struct declarations.

简单类型Simple types

C # 提供一组称为 简单类型 的预定义结构类型。C# provides a set of predefined struct types called the simple types. 简单类型通过保留字标识,但是这些保留字只是命名空间中预定义的结构类型的别名 System ,如下表中所述。The simple types are identified through reserved words, but these reserved words are simply aliases for predefined struct types in the System namespace, as described in the table below.

保留字Reserved word 别名类型Aliased type
sbyte System.SByte
byte System.Byte
short System.Int16
ushort System.UInt16
int System.Int32
uint System.UInt32
long System.Int64
ulong System.UInt64
char System.Char
float System.Single
double System.Double
bool System.Boolean
decimal System.Decimal

因为简单类型是结构类型的别名,所以每个简单类型都具有成员。Because a simple type aliases a struct type, every simple type has members. 例如, int 具有在中声明的成员 System.Int32 和从继承的成员 System.Object ,并且允许以下语句:For example, int has the members declared in System.Int32 and the members inherited from System.Object, and the following statements are permitted:

int i = int.MaxValue;           // System.Int32.MaxValue constant
string s = i.ToString();        // System.Int32.ToString() instance method
string t = 123.ToString();      // System.Int32.ToString() instance method

简单类型不同于其他结构类型,简单类型允许某些附加操作:The simple types differ from other struct types in that they permit certain additional operations:

  • 大多数简单类型允许通过) (文本编写 文本 来创建值。Most simple types permit values to be created by writing literals (Literals). 例如, 123 是类型的文本 int'a' 是类型的文本 charFor example, 123 is a literal of type int and 'a' is a literal of type char. 通常,c # 不会为结构类型的文本提供任何设置,并且最终总是通过这些结构类型的实例构造函数创建其他结构类型的非默认值。C# makes no provision for literals of struct types in general, and non-default values of other struct types are ultimately always created through instance constructors of those struct types.
  • 如果表达式的操作数都是简单类型常量,则编译器可能会在编译时计算表达式。When the operands of an expression are all simple type constants, it is possible for the compiler to evaluate the expression at compile-time. 此类表达式称为) constant_expression (常数表达式Such an expression is known as a constant_expression (Constant expressions). 涉及其他结构类型定义的运算符的表达式不会被视为常量表达式。Expressions involving operators defined by other struct types are not considered to be constant expressions.
  • 通过 const 声明,可以声明简单类型的常量) (常数Through const declarations it is possible to declare constants of the simple types (Constants). 不能有其他结构类型的常量,但字段会提供类似的效果 static readonlyIt is not possible to have constants of other struct types, but a similar effect is provided by static readonly fields.
  • 涉及简单类型的转换可以参与对由其他结构类型定义的转换运算符的计算,但用户定义的转换运算符永远不能参与对其他用户定义的运算符的求值 (计算用户定义的转换) 。Conversions involving simple types can participate in evaluation of conversion operators defined by other struct types, but a user-defined conversion operator can never participate in evaluation of another user-defined operator (Evaluation of user-defined conversions).

整型Integral types

C # 支持9整型类型: sbytebyteshort 、、、、、 ushort int uint long ulongcharC# supports nine integral types: sbyte, byte, short, ushort, int, uint, long, ulong, and char. 整数类型具有以下大小和值范围:The integral types have the following sizes and ranges of values:

  • sbyte 类型表示有符号的8位整数,其值介于-128 和127之间。The sbyte type represents signed 8-bit integers with values between -128 and 127.
  • byte 类型表示无符号的8位整数,其值介于0到255之间。The byte type represents unsigned 8-bit integers with values between 0 and 255.
  • short 类型表示有符号的16位整数,其值介于-32768 和32767之间。The short type represents signed 16-bit integers with values between -32768 and 32767.
  • ushort 类型表示值介于0到65535之间的16位无符号整数。The ushort type represents unsigned 16-bit integers with values between 0 and 65535.
  • int 类型表示有符号32位整数,其值介于-2147483648 和2147483647之间。The int type represents signed 32-bit integers with values between -2147483648 and 2147483647.
  • uint 类型表示无符号32位整数,其值介于0和4294967295之间。The uint type represents unsigned 32-bit integers with values between 0 and 4294967295.
  • long 类型表示有符号64位整数,其值介于-9223372036854775808 和9223372036854775807之间。The long type represents signed 64-bit integers with values between -9223372036854775808 and 9223372036854775807.
  • ulong 类型表示值介于0和18446744073709551615之间的未签名64位整数。The ulong type represents unsigned 64-bit integers with values between 0 and 18446744073709551615.
  • char 类型表示值介于0到65535之间的16位无符号整数。The char type represents unsigned 16-bit integers with values between 0 and 65535. char 类型的可能值集与 Unicode 字符集相对应。The set of possible values for the char type corresponds to the Unicode character set. 尽管与 char 具有相同的表示形式 ushort ,但并不允许在一种类型上进行所有允许的操作。Although char has the same representation as ushort, not all operations permitted on one type are permitted on the other.

整型一元运算符和二元运算符始终操作有符号32位精度、无符号32位精度、有符号64位精度或无符号的64位精度:The integral-type unary and binary operators always operate with signed 32-bit precision, unsigned 32-bit precision, signed 64-bit precision, or unsigned 64-bit precision:

  • 对于一元 +~ 运算符,操作数转换为类型 T ,其中 T 是、、和中的第一个, int uint long ulong 可以完全表示操作数的所有可能值。For the unary + and ~ operators, the operand is converted to type T, where T is the first of int, uint, long, and ulong that can fully represent all possible values of the operand. 然后使用类型的精度执行该操作 T ,结果的类型为 TThe operation is then performed using the precision of type T, and the type of the result is T.
  • 对于一元 - 运算符,操作数转换为类型 T ,其中 Tint 和的第一个 long 可以完全表示操作数的所有可能值。For the unary - operator, the operand is converted to type T, where T is the first of int and long that can fully represent all possible values of the operand. 然后使用类型的精度执行该操作 T ,结果的类型为 TThe operation is then performed using the precision of type T, and the type of the result is T. 一元 - 运算符不能应用于类型的操作数 ulongThe unary - operator cannot be applied to operands of type ulong.
  • 对于二进制、、、、、、、、、、、、、、、、、、、、 + - * / % & ^ | == != > < >=<= 运算符,操作数将转换为类型 T ,其中 T 是、、和中的第一个 intuint long ulong 可以完全表示这两个操作数的所有可能值。For the binary +, -, *, /, %, &, ^, |, ==, !=, >, <, >=, and <= operators, the operands are converted to type T, where T is the first of int, uint, long, and ulong that can fully represent all possible values of both operands. 然后使用类型的精度执行该操作 T ,结果的类型为 T (或 bool 关系运算符) 的。The operation is then performed using the precision of type T, and the type of the result is T (or bool for the relational operators). 不允许一个操作数的类型为,另一个操作数的 long 类型为 ulong 具有二元运算符的类型。It is not permitted for one operand to be of type long and the other to be of type ulong with the binary operators.
  • 对于二元 <<>> 运算符,左操作数转换为类型 T ,其中 T 是、、和中的第 int 一个 uintlong ulong 可以完全表示操作数的所有可能值。For the binary << and >> operators, the left operand is converted to type T, where T is the first of int, uint, long, and ulong that can fully represent all possible values of the operand. 然后使用类型的精度执行该操作 T ,结果的类型为 TThe operation is then performed using the precision of type T, and the type of the result is T.

char类型分类为整型,但不同于其他整数类型的方法有两种:The char type is classified as an integral type, but it differs from the other integral types in two ways:

  • 无法将其他类型隐式转换为 char 类型。There are no implicit conversions from other types to the char type. 具体而言,即使 sbytebyteushort 类型具有使用类型完全可表示的值范围 char ,从、或进行的隐式转换 sbyte byteushort char 不存在。In particular, even though the sbyte, byte, and ushort types have ranges of values that are fully representable using the char type, implicit conversions from sbyte, byte, or ushort to char do not exist.
  • char必须将类型的常量作为 character_literal 写入,或者作为与强制转换为类型的 integer_literal 一起写入 charConstants of the char type must be written as character_literal s or as integer_literal s in combination with a cast to type char. 例如,(char)10'\x000A' 相同。For example, (char)10 is the same as '\x000A'.

checkedunchecked 运算符和语句用于控制整型算术运算和转换的溢出检查, (选中和未选中的运算符) 。The checked and unchecked operators and statements are used to control overflow checking for integral-type arithmetic operations and conversions (The checked and unchecked operators). checked 上下文中,溢出会生成编译时错误,或导致 System.OverflowException 引发。In a checked context, an overflow produces a compile-time error or causes a System.OverflowException to be thrown. unchecked 上下文中,将忽略溢出,并且不会丢弃任何不适合目标类型的高序位。In an unchecked context, overflows are ignored and any high-order bits that do not fit in the destination type are discarded.

浮点类型Floating point types

C # 支持两个浮点类型: floatdoubleC# supports two floating point types: float and double. floatdouble 类型使用32位单精度和64位双精度 IEEE 754 格式表示,这些格式提供以下值集:The float and double types are represented using the 32-bit single-precision and 64-bit double-precision IEEE 754 formats, which provide the following sets of values:

  • 正零和负零。Positive zero and negative zero. 在大多数情况下,正零和负零的行为与简单值零的行为相同,但某些运算区分) 的两个 (除法运算符In most situations, positive zero and negative zero behave identically as the simple value zero, but certain operations distinguish between the two (Division operator).
  • 正无穷大和负无穷大。Positive infinity and negative infinity. 无穷大是由非零数除以零等运算产生的。Infinities are produced by such operations as dividing a non-zero number by zero. 例如,1.0 / 0.0 产生正无穷,-1.0 / 0.0 产生负无穷。For example, 1.0 / 0.0 yields positive infinity, and -1.0 / 0.0 yields negative infinity.
  • 非数字 值,通常缩写为 NaN。The Not-a-Number value, often abbreviated NaN. NaN 是由无效的浮点运算生成的,例如用零除以零。NaNs are produced by invalid floating-point operations, such as dividing zero by zero.
  • 窗体的非零值的有限集 s * m * 2^e ,其中, s 为1或-1,并且 m 和由 e 特定的浮点类型确定:对于、和, float 0 < m < 2^24 -149 <= e <= 104double 、和 0 < m < 2^53 -1075 <= e <= 970The finite set of non-zero values of the form s * m * 2^e, where s is 1 or -1, and m and e are determined by the particular floating-point type: For float, 0 < m < 2^24 and -149 <= e <= 104, and for double, 0 < m < 2^53 and -1075 <= e <= 970. 非标准化浮点数被视为有效的非零值。Denormalized floating-point numbers are considered valid non-zero values.

float 类型可以表示从大约到的值, 1.5 * 10^-45 3.4 * 10^38 精度为7位。The float type can represent values ranging from approximately 1.5 * 10^-45 to 3.4 * 10^38 with a precision of 7 digits.

double 类型可以表示从大约 5.0 * 10^-3241.7 × 10^308 15-16 位的值。The double type can represent values ranging from approximately 5.0 * 10^-324 to 1.7 × 10^308 with a precision of 15-16 digits.

如果二元运算符的一个操作数为浮点类型,则另一个操作数必须为整型类型或浮点类型,并且运算将按如下方式计算:If one of the operands of a binary operator is of a floating-point type, then the other operand must be of an integral type or a floating-point type, and the operation is evaluated as follows:

  • 如果其中一个操作数为整型类型,则该操作数将转换为另一个操作数的浮点类型。If one of the operands is of an integral type, then that operand is converted to the floating-point type of the other operand.
  • 然后,如果任意一个操作数的类型为 double ,则将另一个操作数转换为 double ,使用至少 double 范围和精度执行运算,并且结果的类型为 double (或 bool 关系运算符) 。Then, if either of the operands is of type double, the other operand is converted to double, the operation is performed using at least double range and precision, and the type of the result is double (or bool for the relational operators).
  • 否则,使用至少 float 范围和精度执行操作,并且结果的类型为 float (或 bool 关系运算符) 。Otherwise, the operation is performed using at least float range and precision, and the type of the result is float (or bool for the relational operators).

浮点运算符(包括赋值运算符)从不产生异常。The floating-point operators, including the assignment operators, never produce exceptions. 相反,在异常情况下,浮点运算产生零、无穷或 NaN,如下所述:Instead, in exceptional situations, floating-point operations produce zero, infinity, or NaN, as described below:

  • 如果浮点运算的结果对于目标格式来说太小,则运算的结果将变为正零或负零。If the result of a floating-point operation is too small for the destination format, the result of the operation becomes positive zero or negative zero.
  • 如果浮点运算的结果对于目标格式来说太大,则运算的结果将变为正无穷或负无穷。If the result of a floating-point operation is too large for the destination format, the result of the operation becomes positive infinity or negative infinity.
  • 如果浮点运算无效,则运算的结果将变成 NaN。If a floating-point operation is invalid, the result of the operation becomes NaN.
  • 如果浮点运算的一个或两个操作数都是 NaN,则运算结果变为 NaN。If one or both operands of a floating-point operation is NaN, the result of the operation becomes NaN.

与运算的结果类型相比,浮点运算的精度可能更高。Floating-point operations may be performed with higher precision than the result type of the operation. 例如,某些硬件体系结构支持比类型更大的范围和精度的 "扩展" 或 "长双精度" 浮点类型 double ,并使用这种更高的精度类型隐式执行所有浮点运算。For example, some hardware architectures support an "extended" or "long double" floating-point type with greater range and precision than the double type, and implicitly perform all floating-point operations using this higher precision type. 仅在性能较高的情况下才能执行此类硬件体系结构来执行精度较低的浮点运算,而不是要求实现实现使的性能和精度,c # 允许将更高的精度类型用于所有浮点运算。Only at excessive cost in performance can such hardware architectures be made to perform floating-point operations with less precision, and rather than require an implementation to forfeit both performance and precision, C# allows a higher precision type to be used for all floating-point operations. 除了提供更精确的结果,这种情况很少会带来任何实实在在的影响。Other than delivering more precise results, this rarely has any measurable effects. 但是,在窗体的表达式中 x * y / z ,乘法产生的结果超出 double 范围,而后续除法会将临时结果返回到 double 范围中,这种情况下,以较高的范围格式计算表达式可能导致生成有限的结果而不是无限大。However, in expressions of the form x * y / z, where the multiplication produces a result that is outside the double range, but the subsequent division brings the temporary result back into the double range, the fact that the expression is evaluated in a higher range format may cause a finite result to be produced instead of an infinity.

十进制类型The decimal type

decimal 类型是适用于财务和货币计算的 128 位数据类型。The decimal type is a 128-bit data type suitable for financial and monetary calculations. decimal 类型可以表示范围从 1.0 * 10^-28 到约 7.9 * 10^28 28-29 的值。The decimal type can represent values ranging from 1.0 * 10^-28 to approximately 7.9 * 10^28 with 28-29 significant digits.

类型的有限值集 decimal 的形式为 (-1)^s * c * 10^-e ,其中符号 s 为0或1,系数 c 由指定 0 <= *c* < 2^96 ,刻度 e 为这样 0 <= e <= 28 。此 decimal 类型不支持有符号的零、无穷大或 NaN。The finite set of values of type decimal are of the form (-1)^s * c * 10^-e, where the sign s is 0 or 1, the coefficient c is given by 0 <= *c* < 2^96, and the scale e is such that 0 <= e <= 28.The decimal type does not support signed zeros, infinities, or NaN's. decimal表示为96位整数,由10的幂进行缩放。A decimal is represented as a 96-bit integer scaled by a power of ten. 对于 decimal 绝对值小于 1.0m 的值,该值精确到28位小数,但没有进一步。For decimals with an absolute value less than 1.0m, the value is exact to the 28th decimal place, but no further. 对于 decimal 绝对值大于或等于的 1.0m 值,该值精确到28或29位。For decimals with an absolute value greater than or equal to 1.0m, the value is exact to 28 or 29 digits. floatdouble 数据类型相反,十进制小数值(如0.1)可精确表示为 decimal 表示形式。Contrary to the float and double data types, decimal fractional numbers such as 0.1 can be represented exactly in the decimal representation. floatdouble 表示中,此类数字通常为无限小数,使这些表示形式更容易出现舍入错误。In the float and double representations, such numbers are often infinite fractions, making those representations more prone to round-off errors.

如果二元运算符的一个操作数为类型 decimal ,则另一个操作数必须为整型类型或类型 decimalIf one of the operands of a binary operator is of type decimal, then the other operand must be of an integral type or of type decimal. 如果存在整数类型操作数,则在执行操作之前会将其转换为 decimalIf an integral type operand is present, it is converted to decimal before the operation is performed.

对类型的值执行运算的结果 decimal 是:根据每个运算符的定义,计算精确结果 (保留小数位数) 然后舍入以适合表示形式。The result of an operation on values of type decimal is that which would result from calculating an exact result (preserving scale, as defined for each operator) and then rounding to fit the representation. 结果将舍入为最接近的可表示值,如果结果同样接近两个可表示的值,则为其值在最小有效位位置的偶数 (称为 "银行家舍入" ) 。Results are rounded to the nearest representable value, and, when a result is equally close to two representable values, to the value that has an even number in the least significant digit position (this is known as "banker's rounding"). 如果结果为零,则其符号始终为0,小数位数为0。A zero result always has a sign of 0 and a scale of 0.

如果十进制算术运算生成的值小于或等于 5 * 10^-29 绝对值,则运算的结果将变为零。If a decimal arithmetic operation produces a value less than or equal to 5 * 10^-29 in absolute value, the result of the operation becomes zero. 如果 decimal 算术运算生成的结果对于该格式而言太大 decimalSystem.OverflowException 则会引发。If a decimal arithmetic operation produces a result that is too large for the decimal format, a System.OverflowException is thrown.

decimal 类型具有比浮点类型更高的精度,但范围更小。The decimal type has greater precision but smaller range than the floating-point types. 因此,从浮点类型到的转换 decimal 可能会产生溢出异常,而从 decimal 到浮点类型的转换可能会导致精度损失。Thus, conversions from the floating-point types to decimal might produce overflow exceptions, and conversions from decimal to the floating-point types might cause loss of precision. 由于这些原因,浮点类型与之间不存在隐式转换, decimal 并且没有显式强制转换,因此不能 decimal 在同一个表达式中混合使用浮点和操作数。For these reasons, no implicit conversions exist between the floating-point types and decimal, and without explicit casts, it is not possible to mix floating-point and decimal operands in the same expression.

Bool 类型The bool type

bool类型表示布尔逻辑数量。The bool type represents boolean logical quantities. 类型的可能值 booltruefalseThe possible values of type bool are true and false.

和其他类型之间不存在标准转换 boolNo standard conversions exist between bool and other types. 特别是,该 bool 类型是独特的,独立于整数类型,并且 bool 值不能用于替代整数值,反之亦然。In particular, the bool type is distinct and separate from the integral types, and a bool value cannot be used in place of an integral value, and vice versa.

在 C 和 c + + 语言中,为零整数或浮点值,或者 null 指针可转换为布尔值 false 、非零整数或浮点值或非 null 指针可以转换为布尔值 trueIn the C and C++ languages, a zero integral or floating-point value, or a null pointer can be converted to the boolean value false, and a non-zero integral or floating-point value, or a non-null pointer can be converted to the boolean value true. 在 c # 中,此类转换通过将整数或浮点值显式比较为零来实现,或通过将对象引用显式与进行比较来实现 nullIn C#, such conversions are accomplished by explicitly comparing an integral or floating-point value to zero, or by explicitly comparing an object reference to null.

枚举类型Enumeration types

枚举类型是具有已命名常数的不同类型。An enumeration type is a distinct type with named constants. 每个枚举类型都有一个基础类型,该类型必须是、、、、 byte sbyte short ushort intuint longulongEvery enumeration type has an underlying type, which must be byte, sbyte, short, ushort, int, uint, long or ulong. 枚举类型的值集与基础类型的值集相同。The set of values of the enumeration type is the same as the set of values of the underlying type. 枚举类型的值不局限于命名常量的值。Values of the enumeration type are not restricted to the values of the named constants. 枚举类型是通过枚举声明定义的, (枚举 声明) 。Enumeration types are defined through enumeration declarations (Enum declarations).

可为 null 的类型Nullable types

可以为 null 的类型可以表示其 基础类型 的所有值以及其他 null 值。A nullable type can represent all values of its underlying type plus an additional null value. 写入一个可以为 null 的类型 T? ,其中 T 是基础类型。A nullable type is written T?, where T is the underlying type. 此语法是的速记 System.Nullable<T> ,这两种形式可互换使用。This syntax is shorthand for System.Nullable<T>, and the two forms can be used interchangeably.

不可以为 null 的值类型 与任何) 以外的任何值类型 System.Nullable<T> 以及任何的速记 T? (,以及任何被 T 约束为不可为 null 的值类型的类型参数 (即,具有约束的任何类型参数 struct) 。A non-nullable value type conversely is any value type other than System.Nullable<T> and its shorthand T? (for any T), plus any type parameter that is constrained to be a non-nullable value type (that is, any type parameter with a struct constraint). System.Nullable<T>类型为 T) 指定 (类型参数约束的值类型约束,这意味着可以为 null 的类型的基础类型可以是任何不可以为 null 的值类型。The System.Nullable<T> type specifies the value type constraint for T (Type parameter constraints), which means that the underlying type of a nullable type can be any non-nullable value type. 可以为 null 的类型的基础类型不能是可以为 null 的类型或引用类型。The underlying type of a nullable type cannot be a nullable type or a reference type. 例如, int??string? 是无效类型。For example, int?? and string? are invalid types.

可以为 null 的类型的实例 T? 具有两个公共只读属性:An instance of a nullable type T? has two public read-only properties:

  • HasValue类型的属性boolA HasValue property of type bool
  • Value类型的属性TA Value property of type T

为 true 的实例被 HasValue 称为非 null。An instance for which HasValue is true is said to be non-null. 非 null 实例包含已知值并 Value 返回该值。A non-null instance contains a known value and Value returns that value.

为 false 的实例 HasValue 称为 null。An instance for which HasValue is false is said to be null. 空实例具有未定义的值。A null instance has an undefined value. 尝试读取 Value null 实例的将导致 System.InvalidOperationException 引发。Attempting to read the Value of a null instance causes a System.InvalidOperationException to be thrown. 访问 Value 可以为 null 的实例的属性的过程称为 解包The process of accessing the Value property of a nullable instance is referred to as unwrapping.

除了默认构造函数,每个可以为 null 的类型 T? 都有一个公共构造函数,该构造函数采用类型的单个自变量 TIn addition to the default constructor, every nullable type T? has a public constructor that takes a single argument of type T. 给定 x 类型的值 T ,它是形式的构造函数调用Given a value x of type T, a constructor invocation of the form

new T?(x)

创建属性为的非 null 实例 T? Value xcreates a non-null instance of T? for which the Value property is x. 为给定的值创建可为 null 的类型的非 null 实例的过程称为 包装The process of creating a non-null instance of a nullable type for a given value is referred to as wrapping.

可以从文本中获取隐式转换, null 以将 T? Null 文本转换 () 和转换 TT? (隐式可为 null 的转换) 。Implicit conversions are available from the null literal to T? (Null literal conversions) and from T to T? (Implicit nullable conversions).

引用类型Reference types

引用类型是类类型、接口类型、数组类型或委托类型。A reference type is a class type, an interface type, an array type, or a delegate type.

reference_type
    : class_type
    | interface_type
    | array_type
    | delegate_type
    ;

class_type
    : type_name
    | 'object'
    | 'dynamic'
    | 'string'
    ;

interface_type
    : type_name
    ;

array_type
    : non_array_type rank_specifier+
    ;

non_array_type
    : type
    ;

rank_specifier
    : '[' dim_separator* ']'
    ;

dim_separator
    : ','
    ;

delegate_type
    : type_name
    ;

引用类型值是对类型的 *实例 _ 的引用,后者称为 _ object *。A reference type value is a reference to an instance _ of the type, the latter known as an _object**. 此特殊值 null 与所有引用类型兼容,并指示缺少实例。The special value null is compatible with all reference types and indicates the absence of an instance.

课程类型Class types

类类型定义包含数据 (成员的数据结构,该数据结构) 、函数成员 (方法、属性、事件、索引器、运算符、实例构造函数、析构函数和静态构造函数) 以及嵌套类型。A class type defines a data structure that contains data members (constants and fields), function members (methods, properties, events, indexers, operators, instance constructors, destructors and static constructors), and nested types. 类类型支持继承,这是一个派生类可以扩展和特殊化基类的机制。Class types support inheritance, a mechanism whereby derived classes can extend and specialize base classes. 类类型的实例是使用 object_creation_expression s (对象创建表达式) 创建的。Instances of class types are created using object_creation_expression s (Object creation expressions).

类中对类类型进行了说明。Class types are described in Classes.

某些预定义的类类型在 c # 语言中具有特殊含义,如下表中所述。Certain predefined class types have special meaning in the C# language, as described in the table below.

类类型Class type 说明Description
System.Object 所有其他类型的最终基类。The ultimate base class of all other types. 请参阅 对象类型See The object type.
System.String C # 语言的字符串类型。The string type of the C# language. 请参阅 字符串类型See The string type.
System.ValueType 所有值类型的基类。The base class of all value types. 请参阅 system.object 类型See The System.ValueType type.
System.Enum 所有枚举类型的基类。The base class of all enum types. 请参阅 枚举See Enums.
System.Array 所有数组类型的基类。The base class of all array types. 请参阅数组See Arrays.
System.Delegate 所有委托类型的基类。The base class of all delegate types. 请参阅 委托See Delegates.
System.Exception 所有异常类型的基类。The base class of all exception types. 请参见 异常See Exceptions.

对象类型The object type

object类类型是所有其他类型的最终基类。The object class type is the ultimate base class of all other types. C # 中的每个类型都直接或间接从 object 类类型派生。Every type in C# directly or indirectly derives from the object class type.

关键字 object 只是预定义类的别名 System.ObjectThe keyword object is simply an alias for the predefined class System.Object.

动态类型The dynamic type

dynamic类型(如 object )可引用任何对象。The dynamic type, like object, can reference any object. 将运算符应用于类型的表达式时 dynamic ,其解决方法会推迟到程序运行。When operators are applied to expressions of type dynamic, their resolution is deferred until the program is run. 因此,如果运算符无法合法地应用于被引用对象,则在编译过程中不会提供错误。Thus, if the operator cannot legally be applied to the referenced object, no error is given during compilation. 当运算符的解析在运行时失败时,将引发异常。Instead an exception will be thrown when resolution of the operator fails at run-time.

其目的是允许动态绑定,这在 动态绑定中进行了详细说明。Its purpose is to allow dynamic binding, which is described in detail in Dynamic binding.

dynamic 被视为等同于, object 但以下方面除外:dynamic is considered identical to object except in the following respects:

  • 对类型的表达式的操作 dynamic 可以动态绑定 (动态绑定) 。Operations on expressions of type dynamic can be dynamically bound (Dynamic binding).
  • dynamic object 如果两个都是候选项,则类型推理 (类型推理) 优先使用。Type inference (Type inference) will prefer dynamic over object if both are candidates.

由于这种等效性,以下内容包含:Because of this equivalence, the following holds:

  • 在和之间存在隐式的标识转换, object dynamicdynamic 使用替换 objectThere is an implicit identity conversion between object and dynamic, and between constructed types that are the same when replacing dynamic with object
  • 与之间的隐式和显式转换 object 也适用于和 dynamicImplicit and explicit conversions to and from object also apply to and from dynamic.
  • 替换为时相同的方法签名被 dynamic object 视为相同的签名Method signatures that are the same when replacing dynamic with object are considered the same signature
  • 类型 dynamic object 在运行时不可区分。The type dynamic is indistinguishable from object at run-time.
  • 类型的表达式 dynamic 称为 动态表达式An expression of the type dynamic is referred to as a dynamic expression.

字符串类型The string type

string类型是直接从继承的密封类类型 objectThe string type is a sealed class type that inherits directly from object. 类的实例 string 表示 Unicode 字符串。Instances of the string class represent Unicode character strings.

string可以将类型的值作为字符串文本写入 (字符串文本) 。Values of the string type can be written as string literals (String literals).

关键字 string 只是预定义类的别名 System.StringThe keyword string is simply an alias for the predefined class System.String.

接口类型Interface types

接口定义协定。An interface defines a contract. 实现接口的类或结构必须遵循它的协定。A class or struct that implements an interface must adhere to its contract. 接口可以从多个基接口继承,类或结构可以实现多个接口。An interface may inherit from multiple base interfaces, and a class or struct may implement multiple interfaces.

接口类型在 接口中进行了介绍。Interface types are described in Interfaces.

数组类型Array types

数组是一种数据结构,其中包含零个或多个通过计算索引访问的变量。An array is a data structure that contains zero or more variables which are accessed through computed indices. 数组中的变量(亦称为数组的元素)均为同一种类型,我们将这种类型称为数组的元素类型。The variables contained in an array, also called the elements of the array, are all of the same type, and this type is called the element type of the array.

数组中介绍了数组类型。Array types are described in Arrays.

委托类型Delegate types

委托是指一个或多个方法的数据结构。A delegate is a data structure that refers to one or more methods. 对于实例方法,它还引用其相应的对象实例。For instance methods, it also refers to their corresponding object instances.

C 或 c + + 中委托的最接近等效项是函数指针,但函数指针只能引用静态函数,而委托可以引用静态和实例方法。The closest equivalent of a delegate in C or C++ is a function pointer, but whereas a function pointer can only reference static functions, a delegate can reference both static and instance methods. 在后一种情况下,委托不仅存储对方法入口点的引用,还存储对调用方法的对象实例的引用。In the latter case, the delegate stores not only a reference to the method's entry point, but also a reference to the object instance on which to invoke the method.

委托中介绍了委托类型。Delegate types are described in Delegates.

装箱和取消装箱Boxing and unboxing

装箱和取消装箱的概念是 c # 类型系统的核心。The concept of boxing and unboxing is central to C#'s type system. 它通过允许将任何 value_type 值转换为类型或从类型转换,来在 value_type s 和 reference_type 之间提供桥梁 objectIt provides a bridge between value_type s and reference_type s by permitting any value of a value_type to be converted to and from type object. 装箱和取消装箱可实现类型系统的统一视图,其中,任何类型的值最终都可以被视为对象。Boxing and unboxing enables a unified view of the type system wherein a value of any type can ultimately be treated as an object.

装箱转换Boxing conversions

装箱转换允许 value_type 隐式转换为 reference_typeA boxing conversion permits a value_type to be implicitly converted to a reference_type. 存在以下装箱转换:The following boxing conversions exist:

  • 从任何 value_type 到类型 objectFrom any value_type to the type object.
  • 从任何 value_type 到类型 System.ValueTypeFrom any value_type to the type System.ValueType.
  • 从任何 non_nullable_value_typevalue_type 实现的任何 interface_typeFrom any non_nullable_value_type to any interface_type implemented by the value_type.
  • 从任何 nullable_typenullable_type 基础类型实现的任何 interface_typeFrom any nullable_type to any interface_type implemented by the underlying type of the nullable_type.
  • 从任何 enum_type 到类型 System.EnumFrom any enum_type to the type System.Enum.
  • 从包含基础 enum_type 的任何 nullable_type 到类型 System.EnumFrom any nullable_type with an underlying enum_type to the type System.Enum.
  • 请注意,如果在运行时将从值类型转换为引用类型 (隐式转换涉及) 的类型参数 ,则从类型参数进行的隐式转换将作为装箱转换执行。Note that an implicit conversion from a type parameter will be executed as a boxing conversion if at run-time it ends up converting from a value type to a reference type (Implicit conversions involving type parameters).

non_nullable_value_type 的值装箱包括分配对象实例并将 non_nullable_value_type 值复制到该实例中。Boxing a value of a non_nullable_value_type consists of allocating an object instance and copying the non_nullable_value_type value into that instance.

如果将 nullable_type 的值装箱 null () 的值 HasValue false ,或将基础值解包和装箱的结果,则会生成空引用。Boxing a value of a nullable_type produces a null reference if it is the null value (HasValue is false), or the result of unwrapping and boxing the underlying value otherwise.

将应该构想的 non_nullable_value_type 值装箱的实际过程最好通过泛型 装箱类 的存在来进行解释,这将表现如下:The actual process of boxing a value of a non_nullable_value_type is best explained by imagining the existence of a generic boxing class, which behaves as if it were declared as follows:

sealed class Box<T>: System.ValueType
{
    T value;

    public Box(T t) {
        value = t;
    }
}

类型为的值的装箱 v T 现在包含执行表达式 new Box<T>(v) ,并将生成的实例作为类型的值返回 objectBoxing of a value v of type T now consists of executing the expression new Box<T>(v), and returning the resulting instance as a value of type object. 因此,语句Thus, the statements

int i = 123;
object box = i;

概念上对应于conceptually correspond to

int i = 123;
object box = new Box<int>(i);

如上所示的装箱类 Box<T> 实际上并不存在,装箱值的动态类型实际上不是类类型。A boxing class like Box<T> above doesn't actually exist and the dynamic type of a boxed value isn't actually a class type. 相反,类型的装箱值 T 具有动态类型 T ,使用运算符的动态类型检查 is 只引用类型 TInstead, a boxed value of type T has the dynamic type T, and a dynamic type check using the is operator can simply reference type T. 例如,For example,

int i = 123;
object box = i;
if (box is int) {
    Console.Write("Box contains an int");
}

Box contains an int 在控制台上输出字符串 ""。will output the string "Box contains an int" on the console.

装箱转换表示生成装箱的值的副本。A boxing conversion implies making a copy of the value being boxed. 这不同于将 reference_type 转换为类型 object ,在这种情况下,该值会继续引用同一实例,只被视为派生程度较低的类型 objectThis is different from a conversion of a reference_type to type object, in which the value continues to reference the same instance and simply is regarded as the less derived type object. 例如,给定声明For example, given the declaration

struct Point
{
    public int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

以下语句the following statements

Point p = new Point(10, 10);
object box = p;
p.x = 20;
Console.Write(((Point)box).x);

会在控制台上输出值10,因为在的赋值中发生的隐式装箱操作 pbox 导致复制的值 pwill output the value 10 on the console because the implicit boxing operation that occurs in the assignment of p to box causes the value of p to be copied. Point已经声明了 class ,值20将会输出,因为 pbox 将引用相同的实例。Had Point been declared a class instead, the value 20 would be output because p and box would reference the same instance.

取消装箱转换Unboxing conversions

取消装箱转换允许 reference_type 显式转换为 value_typeAn unboxing conversion permits a reference_type to be explicitly converted to a value_type. 存在以下取消装箱转换:The following unboxing conversions exist:

  • 从类型 object 到任意 value_typeFrom the type object to any value_type.
  • 从类型 System.ValueType 到任意 value_typeFrom the type System.ValueType to any value_type.
  • 从任何 interface_type 到实现 interface_type 的任何 non_nullable_value_typeFrom any interface_type to any non_nullable_value_type that implements the interface_type.
  • 从任何 interface_type 到基础类型都实现了 interface_type 的任何 nullable_typeFrom any interface_type to any nullable_type whose underlying type implements the interface_type.
  • 从类型 System.Enum 到任意 enum_typeFrom the type System.Enum to any enum_type.
  • 从类型 System.Enum 到具有基础 enum_type 的任何 nullable_typeFrom the type System.Enum to any nullable_type with an underlying enum_type.
  • 请注意,如果在运行时将从引用类型转换为值类型 (显式动态转换) ,则将以取消装箱转换的形式执行到类型参数的显式转换。Note that an explicit conversion to a type parameter will be executed as an unboxing conversion if at run-time it ends up converting from a reference type to a value type (Explicit dynamic conversions).

non_nullable_value_type 的取消装箱操作包括:首先检查对象实例是否是给定 non_nullable_value_type 的装箱值,然后将值复制到该实例之外。An unboxing operation to a non_nullable_value_type consists of first checking that the object instance is a boxed value of the given non_nullable_value_type, and then copying the value out of the instance.

如果源操作数为,则对 nullable_type 的取消装箱将生成 nullable_type 的 null 值; null 否则,会将对象实例取消装箱的结果包装到 nullable_type 的基础类型中。Unboxing to a nullable_type produces the null value of the nullable_type if the source operand is null, or the wrapped result of unboxing the object instance to the underlying type of the nullable_type otherwise.

引用上一节中所述的虚部装箱类,将对象取消装箱转换 boxvalue_type T 包括执行表达式 ((Box<T>)box).valueReferring to the imaginary boxing class described in the previous section, an unboxing conversion of an object box to a value_type T consists of executing the expression ((Box<T>)box).value. 因此,语句Thus, the statements

object box = 123;
int i = (int)box;

概念上对应于conceptually correspond to

object box = new Box<int>(123);
int i = ((Box<int>)box).value;

对于到给定 non_nullable_value_type 的取消装箱转换在运行时成功,源操作数的值必须是对该 non_nullable_value_type 的装箱值的引用。For an unboxing conversion to a given non_nullable_value_type to succeed at run-time, the value of the source operand must be a reference to a boxed value of that non_nullable_value_type. 如果源操作数为 null ,则 System.NullReferenceException 引发。If the source operand is null, a System.NullReferenceException is thrown. 如果源操作数是对不兼容的对象的引用, System.InvalidCastException 则会引发。If the source operand is a reference to an incompatible object, a System.InvalidCastException is thrown.

对于到给定 nullable_type 的取消装箱转换在运行时成功,源操作数的值必须是 null 或对 nullable_type 基础 non_nullable_value_type 的装箱值的引用。For an unboxing conversion to a given nullable_type to succeed at run-time, the value of the source operand must be either null or a reference to a boxed value of the underlying non_nullable_value_type of the nullable_type. 如果源操作数是对不兼容的对象的引用, System.InvalidCastException 则会引发。If the source operand is a reference to an incompatible object, a System.InvalidCastException is thrown.

构造类型Constructed types

泛型类型声明本身表示一个 未绑定的泛型类型 _,它用作 "蓝图" 以形成多种不同类型,方法是应用 _类型参数*A generic type declaration, by itself, denotes an unbound generic type _ that is used as a "blueprint" to form many different types, by way of applying _type arguments*. 类型参数用尖括号括起来 < , (和 >) 紧随泛型类型的名称。The type arguments are written within angle brackets (< and >) immediately following the name of the generic type. 包含至少一个类型参数的类型称为 *构造类型*A type that includes at least one type argument is called a constructed type. 构造类型可用于语言中可显示类型名称的大多数位置。A constructed type can be used in most places in the language in which a type name can appear. 未绑定的泛型类型只能在 _typeof_expression * (typeof 运算符) 内使用。An unbound generic type can only be used within a _typeof_expression* (The typeof operator).

构造类型还可以在表达式中用作简单名称 (简单 名称) 或 (成员访问) 访问成员。Constructed types can also be used in expressions as simple names (Simple names) or when accessing a member (Member access).

计算 namespace_or_type_name 时,只考虑具有正确数量的类型参数的泛型类型。When a namespace_or_type_name is evaluated, only generic types with the correct number of type parameters are considered. 因此,只要类型具有不同数目的类型参数,就可以使用相同的标识符来识别不同的类型。Thus, it is possible to use the same identifier to identify different types, as long as the types have different numbers of type parameters. 在同一程序中混合泛型和非泛型类时,这很有用:This is useful when mixing generic and non-generic classes in the same program:

namespace Widgets
{
    class Queue {...}
    class Queue<TElement> {...}
}

namespace MyApplication
{
    using Widgets;

    class X
    {
        Queue q1;            // Non-generic Widgets.Queue
        Queue<int> q2;       // Generic Widgets.Queue
    }
}

Type_name 可以标识构造的类型,即使它不直接指定类型参数也是如此。A type_name might identify a constructed type even though it doesn't specify type parameters directly. 如果类型嵌套在泛型类声明中,并且包含声明的实例类型将隐式用于名称查找 (泛型类) 中的嵌套类型 ,则会发生这种情况。This can occur where a type is nested within a generic class declaration, and the instance type of the containing declaration is implicitly used for name lookup (Nested types in generic classes):

class Outer<T>
{
    public class Inner {...}

    public Inner i;                // Type of i is Outer<T>.Inner
}

在不安全代码中,构造类型不能用作) unmanaged_type (指针类型In unsafe code, a constructed type cannot be used as an unmanaged_type (Pointer types).

类型参数Type arguments

类型实参列表中的每个实参只是一 种类型Each argument in a type argument list is simply a type.

type_argument_list
    : '<' type_arguments '>'
    ;

type_arguments
    : type_argument (',' type_argument)*
    ;

type_argument
    : type
    ;

在不安全代码 (不安全代码) 中, type_argument 可能不是指针类型。In unsafe code (Unsafe code), a type_argument may not be a pointer type. 每个类型参数都必须满足相应类型参数的任何约束 (类型参数约束) 。Each type argument must satisfy any constraints on the corresponding type parameter (Type parameter constraints).

打开和关闭的类型Open and closed types

所有类型都可以分类为 *开放式类型 _ 或 _ 关闭类型 *。All types can be classified as either open types _ or _closed types**. 开放式类型是一种涉及类型参数的类型。An open type is a type that involves type parameters. 更具体地说:More specifically:

  • 类型参数定义开放类型。A type parameter defines an open type.
  • 当且仅当数组的元素类型为开放类型时,该类型才是开放类型。An array type is an open type if and only if its element type is an open type.
  • 当且仅当一个或多个类型参数是开放类型时,构造类型是开放类型。A constructed type is an open type if and only if one or more of its type arguments is an open type. 当且仅当其包含类型的一个或多个类型参数或其包含类型 () 是开放类型时,构造的嵌套类型是开放类型。A constructed nested type is an open type if and only if one or more of its type arguments or the type arguments of its containing type(s) is an open type.

关闭的类型是不是开放类型的类型。A closed type is a type that is not an open type.

在运行时,泛型类型声明中的所有代码在通过将类型自变量应用于泛型声明而创建的封闭式构造类型的上下文中执行。At run-time, all of the code within a generic type declaration is executed in the context of a closed constructed type that was created by applying type arguments to the generic declaration. 泛型类型中的每个类型形参都绑定到特定的运行时类型。Each type parameter within the generic type is bound to a particular run-time type. 所有语句和表达式的运行时处理始终出现在关闭的类型中,并且打开的类型仅在编译时处理期间出现。The run-time processing of all statements and expressions always occurs with closed types, and open types occur only during compile-time processing.

每个封闭式构造类型都有自己的静态变量集,它们不与任何其他封闭构造类型共享。Each closed constructed type has its own set of static variables, which are not shared with any other closed constructed types. 由于打开的类型在运行时不存在,因此没有与开放式类型关联的静态变量。Since an open type does not exist at run-time, there are no static variables associated with an open type. 如果两个封闭式构造类型是从同一个未绑定的泛型类型构造的,则这两个封闭式构造类型都是相同的类型,并且其对应的类型参数是相同的类型Two closed constructed types are the same type if they are constructed from the same unbound generic type, and their corresponding type arguments are the same type.

绑定类型和未绑定类型Bound and unbound types

术语 *未绑定类型 _ 引用非泛型类型或未绑定的泛型类型。The term *unbound type _ refers to a non-generic type or an unbound generic type. 术语 _ 绑定类型* 指非泛型类型或构造类型。The term _ bound type* refers to a non-generic type or a constructed type.

未绑定类型引用由类型声明声明的实体。An unbound type refers to the entity declared by a type declaration. 未绑定的泛型类型本身不是类型,不能用作变量、参数或返回值的类型,也不能用作基类型。An unbound generic type is not itself a type, and cannot be used as the type of a variable, argument or return value, or as a base type. 无法引用未绑定的泛型类型的唯一构造是 typeof (typeof 运算符) 的表达式。The only construct in which an unbound generic type can be referenced is the typeof expression (The typeof operator).

满足约束Satisfying constraints

只要引用构造类型或泛型方法,就会根据泛型类型或方法 (类型参数约束) 中声明的类型参数约束来检查提供的类型参数。Whenever a constructed type or generic method is referenced, the supplied type arguments are checked against the type parameter constraints declared on the generic type or method (Type parameter constraints). 对于每个 where 子句,对照 A 每个约束检查对应于命名类型参数的类型自变量,如下所示:For each where clause, the type argument A that corresponds to the named type parameter is checked against each constraint as follows:

  • 如果约束是类类型、接口类型或类型参数,则让我们 C 用提供的类型参数表示约束中出现的任何类型参数。If the constraint is a class type, an interface type, or a type parameter, let C represent that constraint with the supplied type arguments substituted for any type parameters that appear in the constraint. 若要满足约束,必须使用 A 以下方法之一将类型转换为类型 CTo satisfy the constraint, it must be the case that type A is convertible to type C by one of the following:
  • 如果约束是引用类型约束 (class) ,则该类型 A 必须满足以下条件之一:If the constraint is the reference type constraint (class), the type A must satisfy one of the following:
    • A 接口类型、类类型、委托类型或数组类型。A is an interface type, class type, delegate type or array type. 请注意, System.ValueTypeSystem.Enum 是满足此约束的引用类型。Note that System.ValueType and System.Enum are reference types that satisfy this constraint.
    • A 已知为类型参数 (类型参数约束 的类型形参) 。A is a type parameter that is known to be a reference type (Type parameter constraints).
  • 如果约束是值类型约束 (struct) ,则该类型 A 必须满足以下条件之一:If the constraint is the value type constraint (struct), the type A must satisfy one of the following:
    • A 是结构类型或枚举类型,但不能是可以为 null 的类型。A is a struct type or enum type, but not a nullable type. 请注意, System.ValueTypeSystem.Enum 是不满足此约束的引用类型。Note that System.ValueType and System.Enum are reference types that do not satisfy this constraint.
    • A 是具有值类型约束的类型参数, (类型参数约束) 。A is a type parameter having the value type constraint (Type parameter constraints).
  • 如果约束为构造函数约束 new() ,则该类型 A 不得为 abstract ,并且必须具有公共的无参数构造函数。If the constraint is the constructor constraint new(), the type A must not be abstract and must have a public parameterless constructor. 如果满足以下条件之一,则满足此要求:This is satisfied if one of the following is true:
    • A 是一个值类型,因为所有值类型都具有公共默认构造函数 (默认构造 函数) 。A is a value type, since all value types have a public default constructor (Default constructors).
    • A 是具有构造函数约束的类型参数, (类型参数约束) 。A is a type parameter having the constructor constraint (Type parameter constraints).
    • A 是具有值类型约束的类型参数, (类型参数约束) 。A is a type parameter having the value type constraint (Type parameter constraints).
    • A 不是的类, abstract 包含不带参数的显式 public 声明的构造函数。A is a class that is not abstract and contains an explicitly declared public constructor with no parameters.
    • A 不为 abstract ,并且具有默认构造函数 (默认 构造函数) 。A is not abstract and has a default constructor (Default constructors).

如果给定的类型参数不满足一个或多个类型参数的约束,则会发生编译时错误。A compile-time error occurs if one or more of a type parameter's constraints are not satisfied by the given type arguments.

由于类型参数不是继承的,因此永远不会继承约束。Since type parameters are not inherited, constraints are never inherited either. 在下面的示例中, D 需要指定其类型参数上的约束, T 以便 T 满足基类施加的约束 B<T>In the example below, D needs to specify the constraint on its type parameter T so that T satisfies the constraint imposed by the base class B<T>. 与此相反,类 E 无需指定约束,因为它是 List<T> IEnumerable 针对任何实现的 TIn contrast, class E need not specify a constraint, because List<T> implements IEnumerable for any T.

class B<T> where T: IEnumerable {...}

class D<T>: B<T> where T: IEnumerable {...}

class E<T>: B<List<T>> {...}

类型参数Type parameters

类型参数是一个标识符,它指定在运行时参数绑定到的值类型或引用类型。A type parameter is an identifier designating a value type or reference type that the parameter is bound to at run-time.

type_parameter
    : identifier
    ;

由于类型参数可以使用许多不同的实际类型参数进行实例化,因此类型参数与其他类型相比,操作和限制略有不同。Since a type parameter can be instantiated with many different actual type arguments, type parameters have slightly different operations and restrictions than other types. 其中包括:These include:

类型参数只是一种编译时构造。As a type, type parameters are purely a compile-time construct. 在运行时,每个类型参数都绑定到一个运行时类型,该类型是通过向泛型类型声明提供类型参数来指定的。At run-time, each type parameter is bound to a run-time type that was specified by supplying a type argument to the generic type declaration. 因此,使用类型参数声明的变量的类型将在运行时是封闭式构造类型 (打开和关闭的类型) 。Thus, the type of a variable declared with a type parameter will, at run-time, be a closed constructed type (Open and closed types). 所有涉及类型参数的语句和表达式的运行时执行都使用作为该参数的类型参数提供的实际类型。The run-time execution of all statements and expressions involving type parameters uses the actual type that was supplied as the type argument for that parameter.

表达式树类型Expression tree types

*表达式树-允许将 lambda 表达式表示为数据结构而不是可执行代码。*Expression trees _ permit lambda expressions to be represented as data structures instead of executable code. 表达式树是窗体的 _ 表达式树类型* 的值 System.Linq.Expressions.Expression<D> ,其中 D 是任何委托类型。Expression trees are values of _ expression tree types* of the form System.Linq.Expressions.Expression<D>, where D is any delegate type. 对于本规范的其余部分,我们将使用简写形式引用这些类型 Expression<D>For the remainder of this specification we will refer to these types using the shorthand Expression<D>.

如果从 lambda 表达式存在转换为委托类型 D ,则还存在对表达式树类型的转换 Expression<D>If a conversion exists from a lambda expression to a delegate type D, a conversion also exists to the expression tree type Expression<D>. 尽管将 lambda 表达式转换为委托类型会生成一个委托,该委托引用 lambda 表达式的可执行代码,但转换为表达式树类型会创建 lambda 表达式的表达式树表示形式。Whereas the conversion of a lambda expression to a delegate type generates a delegate that references executable code for the lambda expression, conversion to an expression tree type creates an expression tree representation of the lambda expression.

表达式树是 lambda 表达式的有效内存中数据表示形式,并使 lambda 表达式的结构透明和显式。Expression trees are efficient in-memory data representations of lambda expressions and make the structure of the lambda expression transparent and explicit.

与委托类型一样 DExpression<D> 被称为具有参数和返回类型,它们与的类型相同 DJust like a delegate type D, Expression<D> is said to have parameter and return types, which are the same as those of D.

下面的示例将 lambda 表达式表示为可执行代码,并表示为表达式树。The following example represents a lambda expression both as executable code and as an expression tree. 由于存在转换,因此 Func<int,int> 还存在 Expression<Func<int,int>> 以下转换:Because a conversion exists to Func<int,int>, a conversion also exists to Expression<Func<int,int>>:

Func<int,int> del = x => x + 1;                    // Code

Expression<Func<int,int>> exp = x => x + 1;        // Data

按照这些赋值,委托 del 引用返回的方法 x + 1 ,表达式树 exp 引用用于描述表达式的数据结构 x => x + 1Following these assignments, the delegate del references a method that returns x + 1, and the expression tree exp references a data structure that describes the expression x => x + 1.

在将 Expression<D> lambda 表达式转换为表达式树类型时,泛型类型的确切定义以及用于构造表达式树的准确规则都超出了此规范的范围。The exact definition of the generic type Expression<D> as well as the precise rules for constructing an expression tree when a lambda expression is converted to an expression tree type, are both outside the scope of this specification.

要做出显式操作,需要注意以下两项:Two things are important to make explicit:

  • 并非所有 lambda 表达式都可以转换为表达式树。Not all lambda expressions can be converted to expression trees. 例如,具有语句体的 lambda 表达式和包含赋值表达式的 lambda 表达式不能表示。For instance, lambda expressions with statement bodies, and lambda expressions containing assignment expressions cannot be represented. 在这些情况下,转换仍存在,但会在编译时失败。In these cases, a conversion still exists, but will fail at compile-time. 匿名函数转换中详细介绍了这些异常。These exceptions are detailed in Anonymous function conversions.

  • Expression<D> 提供一个实例方法 Compile ,该方法生成类型为的委托 DExpression<D> offers an instance method Compile which produces a delegate of type D:

    Func<int,int> del2 = exp.Compile();
    

    调用此委托将导致执行表达式树所表示的代码。Invoking this delegate causes the code represented by the expression tree to be executed. 因此,根据上面的定义,del 和 del2 是等效的,以下两个语句将具有相同的效果:Thus, given the definitions above, del and del2 are equivalent, and the following two statements will have the same effect:

    int i1 = del(1);
    
    int i2 = del2(1);
    

    执行此代码后, i1 i2 将具有值 2After executing this code, i1 and i2 will both have the value 2.