转换Conversions
*转换 _ 允许将表达式视为特定类型。A *conversion _ enables an expression to be treated as being of a particular type. 转换可能会导致将给定类型的表达式视为具有不同的类型,也可能导致不具有类型的表达式获得类型。A conversion may cause an expression of a given type to be treated as having a different type, or it may cause an expression without a type to get a type. 转换可以是 *隐式* 或 _ explicit *,这确定是否需要显式强制转换。Conversions can be implicit or _*explicit**, and this determines whether an explicit cast is required. 例如,从类型 int
到类型的转换 long
是隐式的,因此类型的表达式 int
可以隐式对待为类型 long
。For instance, the conversion from type int
to type long
is implicit, so expressions of type int
can implicitly be treated as type long
. 相反,从类型 long
到类型的转换 int
是显式的,因此需要显式强制转换。The opposite conversion, from type long
to type int
, is explicit and so an explicit cast is required.
int a = 123;
long b = a; // implicit conversion from int to long
int c = (int) b; // explicit conversion from long to int
某些转换是由语言定义的。Some conversions are defined by the language. 程序还可以定义自己的转换 (用户定义的转换) 。Programs may also define their own conversions (User-defined conversions).
隐式转换Implicit conversions
以下转换归类为隐式转换:The following conversions are classified as implicit conversions:
- 标识转换Identity conversions
- 隐式数值转换Implicit numeric conversions
- 隐式枚举转换Implicit enumeration conversions
- 隐式内插字符串转换Implicit interpolated string conversions
- 隐式可为空转换Implicit nullable conversions
- Null 文本转换Null literal conversions
- 隐式引用转换Implicit reference conversions
- 装箱转换Boxing conversions
- 隐式动态转换Implicit dynamic conversions
- 隐式常量表达式转换Implicit constant expression conversions
- 用户定义的隐式转换User-defined implicit conversions
- 匿名函数转换Anonymous function conversions
- 方法组转换Method group conversions
隐式转换可能会在多种情况下发生,包括函数成员调用 (编译时检查动态重载解析) 、强制转换表达式 (强制转换表达式) ,并 (赋值运算符) 赋值运算符 。Implicit conversions can occur in a variety of situations, including function member invocations (Compile-time checking of dynamic overload resolution), cast expressions (Cast expressions), and assignments (Assignment operators).
预定义的隐式转换始终会成功,并且永远不会引发异常。The pre-defined implicit conversions always succeed and never cause exceptions to be thrown. 正确设计的用户定义隐式转换也应显示这些特征。Properly designed user-defined implicit conversions should exhibit these characteristics as well.
出于转换目的,类型 object
和被 dynamic
视为等效的。For the purposes of conversion, the types object
and dynamic
are considered equivalent.
但是,动态转换 (隐式动态转换 和 显式动态转换) 仅应用于 dynamic
(动态类型) 的类型的表达式。However, dynamic conversions (Implicit dynamic conversions and Explicit dynamic conversions) apply only to expressions of type dynamic
(The dynamic type).
标识转换Identity conversion
标识转换从任何类型转换为同一类型。An identity conversion converts from any type to the same type. 此转换存在,因此,已具有所需类型的实体可被视为可转换为该类型。This conversion exists such that an entity that already has a required type can be said to be convertible to that type.
- 因为和被视为等效的,所以在
object
dynamic
和之间存在一个标识转换,object
dynamic
在将的所有匹配项替换为相同的构造类型之间dynamic
object
。Becauseobject
anddynamic
are considered equivalent there is an identity conversion betweenobject
anddynamic
, and between constructed types that are the same when replacing all occurrences ofdynamic
withobject
.
隐式数值转换Implicit numeric conversions
隐式数值转换为:The implicit numeric conversions are:
- 从
sbyte
到、、、、short
int
long
float
double
或decimal
。Fromsbyte
toshort
,int
,long
,float
,double
, ordecimal
. - 从到、、、、、、、
byte
short
ushort
int
uint
long
ulong
float
double
或decimal
。Frombyte
toshort
,ushort
,int
,uint
,long
,ulong
,float
,double
, ordecimal
. - 从
short
到int
、、、long
float
double
或decimal
。Fromshort
toint
,long
,float
,double
, ordecimal
. - 从到、、、、、
ushort
int
uint
long
ulong
float
double
或decimal
。Fromushort
toint
,uint
,long
,ulong
,float
,double
, ordecimal
. - 从
int
到long
、float
、double
或decimal
。Fromint
tolong
,float
,double
, ordecimal
. - 从
uint
到long
、、、ulong
float
double
或decimal
。Fromuint
tolong
,ulong
,float
,double
, ordecimal
. - 从
long
到float
、double
或decimal
。Fromlong
tofloat
,double
, ordecimal
. - 从
ulong
到float
、double
或decimal
。Fromulong
tofloat
,double
, ordecimal
. - 从到、、、、、、
char
ushort
int
uint
long
ulong
float
double
或decimal
。Fromchar
toushort
,int
,uint
,long
,ulong
,float
,double
, ordecimal
. - 从
float
到double
。Fromfloat
todouble
.
从 int
、、 uint
long
或到之间的转换 ulong
float
long
ulong
double
可能会导致精度损失,但永远不会导致数量级损失。Conversions from int
, uint
, long
, or ulong
to float
and from long
or ulong
to double
may cause a loss of precision, but will never cause a loss of magnitude. 其他隐式数值转换不会丢失任何信息。The other implicit numeric conversions never lose any information.
不存在对类型的隐式转换 char
,因此其他整型类型的值不会自动转换为 char
类型。There are no implicit conversions to the char
type, so values of the other integral types do not automatically convert to the char
type.
隐式枚举转换Implicit enumeration conversions
隐式枚举转换允许 decimal_integer_literal 0
转换为任何 enum_type ,以及基础类型为 enum_type 的任何 nullable_type 。An implicit enumeration conversion permits the decimal_integer_literal 0
to be converted to any enum_type and to any nullable_type whose underlying type is an enum_type. 在后一种情况下,转换将通过转换为基础 enum_type 进行计算,并将结果包装 (可以为 null 的类型) 。In the latter case the conversion is evaluated by converting to the underlying enum_type and wrapping the result (Nullable types).
隐式内插字符串转换Implicit interpolated string conversions
隐式内插字符串转换允许 interpolated_string_expression (内 插字符串) 转换为 System.IFormattable
System.FormattableString
实现) 的或 (System.IFormattable
。An implicit interpolated string conversion permits an interpolated_string_expression (Interpolated strings) to be converted to System.IFormattable
or System.FormattableString
(which implements System.IFormattable
).
应用此转换时,字符串值不是由内插字符串组成的。When this conversion is applied a string value is not composed from the interpolated string. 相反 System.FormattableString
,将创建的实例,如内 插字符串中所述。Instead an instance of System.FormattableString
is created, as further described in Interpolated strings.
隐式可为空转换Implicit nullable conversions
对不可以为 null 的值类型进行操作的预定义隐式转换也可用于这些类型的可以为 null 的形式。Predefined implicit conversions that operate on non-nullable value types can also be used with nullable forms of those types. 对于从不可为 null 的值类型转换为不可为 null 的值类型的每个预定义隐式标识和数值转换 S
T
,存在以下隐式可为 null 的转换:For each of the predefined implicit identity and numeric conversions that convert from a non-nullable value type S
to a non-nullable value type T
, the following implicit nullable conversions exist:
- 从到的隐式转换
S?
T?
。An implicit conversion fromS?
toT?
. - 从到的隐式转换
S
T?
。An implicit conversion fromS
toT?
.
根据中的基础转换,计算隐式可为 null 的转换, S
T
如下所示:Evaluation of an implicit nullable conversion based on an underlying conversion from S
to T
proceeds as follows:
如果可以为 null 的转换从
S?
到T?
:If the nullable conversion is fromS?
toT?
:- 如果源值为 null (
HasValue
属性为 false) ,则结果为类型的 null 值T?
。If the source value is null (HasValue
property is false), the result is the null value of typeT?
. - 否则,转换将作为从到的解包进行计算
S?
S
,后跟从到的基础转换S
T
,然后) 从到的包装 (可以为 null 的类型T
T?
。Otherwise, the conversion is evaluated as an unwrapping fromS?
toS
, followed by the underlying conversion fromS
toT
, followed by a wrapping (Nullable types) fromT
toT?
.
- 如果源值为 null (
如果可以为 null 的转换从
S
到T?
,则会将转换计算为从到的基础转换,S
并将从到T
的换行T
T?
。If the nullable conversion is fromS
toT?
, the conversion is evaluated as the underlying conversion fromS
toT
followed by a wrapping fromT
toT?
.
Null 文本转换Null literal conversions
存在从 null
文本到任何可以为 null 的类型的隐式转换。An implicit conversion exists from the null
literal to any nullable type. 这种转换会生成 null 值, (给定可以为 null 的类型) 可 为 null 的类型。This conversion produces the null value (Nullable types) of the given nullable type.
隐式引用转换Implicit reference conversions
隐式引用转换为:The implicit reference conversions are:
- 从任何 reference_type 到
object
和dynamic
。From any reference_type toobject
anddynamic
. - 从任何 class_type
S
到任何 class_typeT
,S
都是从派生的T
。From any class_typeS
to any class_typeT
, providedS
is derived fromT
. - 从任何 class_type
S
到任何 interface_typeT
,提供的S
实现T
。From any class_typeS
to any interface_typeT
, providedS
implementsT
. - 从任何 interface_type
S
到任何 interface_typeT
,S
都是从派生的T
。From any interface_typeS
to any interface_typeT
, providedS
is derived fromT
. - 在 array_type 具有元素类型的 array_type 中
S
,如果SE
T
TE
满足以下所有条件:From an array_typeS
with an element typeSE
to an array_typeT
with an element typeTE
, provided all of the following are true:S
和T
仅因元素类型而异。S
andT
differ only in element type. 换言之,S
和T
具有相同的维数。In other words,S
andT
have the same number of dimensions.SE
和TE
都是 reference_type。BothSE
andTE
are reference_type s.- 存在从到的隐式引用转换
SE
TE
。An implicit reference conversion exists fromSE
toTE
.
- 从任何 array_type
System.Array
和它实现的接口。From any array_type toSystem.Array
and the interfaces it implements. - 从一维数组类型
S[]
到System.Collections.Generic.IList<T>
及其基接口,前提是存在隐式标识或从到的引用转换S
T
。From a single-dimensional array typeS[]
toSystem.Collections.Generic.IList<T>
and its base interfaces, provided that there is an implicit identity or reference conversion fromS
toT
. - 从任何 delegate_type
System.Delegate
和它实现的接口。From any delegate_type toSystem.Delegate
and the interfaces it implements. - 从 null 文本到任何 reference_type。From the null literal to any reference_type.
- 从任何 reference_type 到 reference_type ,
T
如果它具有隐式标识或到 reference_type 的引用转换T0
,并且T0
具有到的标识转换T
。From any reference_type to a reference_typeT
if it has an implicit identity or reference conversion to a reference_typeT0
andT0
has an identity conversion toT
. - 从任何 reference_type 到接口或委托类型(
T
如果它具有隐式标识或到接口或委托类型的引用转换T0
),并且) 到之间存在可转换的T0
(方差转换T
。From any reference_type to an interface or delegate typeT
if it has an implicit identity or reference conversion to an interface or delegate typeT0
andT0
is variance-convertible (Variance conversion) toT
. - 涉及称为引用类型的类型参数的隐式转换。Implicit conversions involving type parameters that are known to be reference types. 有关涉及类型参数的隐式转换的更多详细信息,请参阅 涉及类型参数的隐式转换 。See Implicit conversions involving type parameters for more details on implicit conversions involving type parameters.
隐式引用转换是 reference_type 之间的转换,这些转换可证明始终成功,因此不需要在运行时进行检查。The implicit reference conversions are those conversions between reference_type s that can be proven to always succeed, and therefore require no checks at run-time.
引用转换、隐式或显式转换决不会更改正在转换的对象的引用标识。Reference conversions, implicit or explicit, never change the referential identity of the object being converted. 换言之,虽然引用转换可以更改引用的类型,但它不会更改引用的对象的类型或值。In other words, while a reference conversion may change the type of the reference, it never changes the type or value of the object being referred to.
装箱转换Boxing conversions
装箱转换允许 value_type 隐式转换为引用类型。A boxing conversion permits a value_type to be implicitly converted to a reference type. 对 object
dynamic
System.ValueType
non_nullable_value_type 实现的任何 interface_type ,都存在从到、、以及的任何 non_nullable_value_type 的装箱转换。A boxing conversion exists from any non_nullable_value_type to object
and dynamic
, to System.ValueType
and to any interface_type implemented by the non_nullable_value_type. 此外,可以将 enum_type 转换为类型 System.Enum
。Furthermore an enum_type can be converted to the type System.Enum
.
如果且仅当存在从基础 non_nullable_value_type 到引用类型的装箱转换,则从 nullable_type 到引用类型的装箱转换。A boxing conversion exists from a nullable_type to a reference type, if and only if a boxing conversion exists from the underlying non_nullable_value_type to the reference type.
如果值类型 I
具有到接口类型的装箱转换 I0
,并且其 I0
标识转换为,则该值类型具有到接口类型的装箱转换 I
。A value type has a boxing conversion to an interface type I
if it has a boxing conversion to an interface type I0
and I0
has an identity conversion to I
.
如果值类型 I
具有到接口类型的装箱转换或委托类型的装箱转换 I0
并且 I0
(方差转换) 为变体,则该值类型具有到的装箱转换 I
。A value type has a boxing conversion to an interface type I
if it has a boxing conversion to an interface or delegate type I0
and I0
is variance-convertible (Variance conversion) to I
.
将 non_nullable_value_type 的值装箱包括分配对象实例并将 value_type 值复制到该实例中。Boxing a value of a non_nullable_value_type consists of allocating an object instance and copying the value_type value into that instance. 结构可以装箱到类型 System.ValueType
,因为这是所有结构的基类 (继承) 。A struct can be boxed to the type System.ValueType
, since that is a base class for all structs (Inheritance).
将 nullable_type 的值装箱将继续执行以下操作:Boxing a value of a nullable_type proceeds as follows:
- 如果源值为 null (
HasValue
属性为 false) ,则结果将为目标类型的空引用。If the source value is null (HasValue
property is false), the result is a null reference of the target type. - 否则,结果将是对
T
源值解包和装箱而生成的装箱的引用。Otherwise, the result is a reference to a boxedT
produced by unwrapping and boxing the source value.
装箱转换中进一步介绍了装箱转换。Boxing conversions are described further in Boxing conversions.
隐式动态转换Implicit dynamic conversions
存在从类型为的表达式到任何类型的隐式动态转换 dynamic
T
。An implicit dynamic conversion exists from an expression of type dynamic
to any type T
. 转换是动态绑定 (动态绑定) ,这意味着将在运行时从表达式的运行时类型中查找隐式转换 T
。The conversion is dynamically bound (Dynamic binding), which means that an implicit conversion will be sought at run-time from the run-time type of the expression to T
. 如果未找到任何转换,则会引发运行时异常。If no conversion is found, a run-time exception is thrown.
请注意,此隐式转换似乎违反了隐式转换开始时的 建议,隐 式转换应永远不会引发异常。Note that this implicit conversion seemingly violates the advice in the beginning of Implicit conversions that an implicit conversion should never cause an exception. 但它不是转换本身,而是 查找 导致异常的转换。However it is not the conversion itself, but the finding of the conversion that causes the exception. 运行时异常的风险在使用动态绑定时是固有的。The risk of run-time exceptions is inherent in the use of dynamic binding. 如果不需要转换的动态绑定,则可以先将该表达式转换为 object
,然后再转换为所需的类型。If dynamic binding of the conversion is not desired, the expression can be first converted to object
, and then to the desired type.
下面的示例阐释了隐式动态转换:The following example illustrates implicit dynamic conversions:
object o = "object"
dynamic d = "dynamic";
string s1 = o; // Fails at compile-time -- no conversion exists
string s2 = d; // Compiles and succeeds at run-time
int i = d; // Compiles but fails at run-time -- no conversion exists
和中的 s2
分配 i
都采用隐式动态转换,在这种情况下,将在运行时暂停操作的绑定。The assignments to s2
and i
both employ implicit dynamic conversions, where the binding of the operations is suspended until run-time. 在运行时,隐式转换从的运行时类型中查找 d
-- string
到目标类型。At run-time, implicit conversions are sought from the run-time type of d
-- string
-- to the target type. 找到到, string
但不能转换为 int
。A conversion is found to string
but not to int
.
隐式常量表达式转换Implicit constant expression conversions
隐式常数表达式转换允许以下转换:An implicit constant expression conversion permits the following conversions:
-
int
sbyte
byte
short
ushort
uint
ulong
如果 constant_expression 的值在目标类型的范围内,则可以将类型的 constant_expression (常数表达式) 转换为类型、、、、或。A constant_expression (Constant expressions) of typeint
can be converted to typesbyte
,byte
,short
,ushort
,uint
, orulong
, provided the value of the constant_expression is within the range of the destination type. -
long
ulong
如果 constant_expression 的值不为负数,则可以将类型的 constant_expression 转换为类型。A constant_expression of typelong
can be converted to typeulong
, provided the value of the constant_expression is not negative.
涉及类型参数的隐式转换Implicit conversions involving type parameters
给定的类型参数存在以下隐式转换 T
:The following implicit conversions exist for a given type parameter T
:
- 从到
T
其有效的基类C
,从到的任何基类,从到所T
C
T
实现的任何接口C
。FromT
to its effective base classC
, fromT
to any base class ofC
, and fromT
to any interface implemented byC
. 在运行时,如果T
是值类型,则转换将作为装箱转换执行。At run-time, ifT
is a value type, the conversion is executed as a boxing conversion. 否则,转换将作为隐式引用转换或标识转换执行。Otherwise, the conversion is executed as an implicit reference conversion or identity conversion. - 从
T
I
T
设置为有效接口中的接口类型,并从设置T
为的任何基接口I
。FromT
to an interface typeI
inT
's effective interface set and fromT
to any base interface ofI
. 在运行时,如果T
是值类型,则转换将作为装箱转换执行。At run-time, ifT
is a value type, the conversion is executed as a boxing conversion. 否则,转换将作为隐式引用转换或标识转换执行。Otherwise, the conversion is executed as an implicit reference conversion or identity conversion. - 从
T
到类型参数U
,T
具体取决于U
) (类型参数约束 。FromT
to a type parameterU
, providedT
depends onU
(Type parameter constraints). 在运行时,如果U
是值类型,则和的T
U
类型必须相同,并且不执行任何转换。At run-time, ifU
is a value type, thenT
andU
are necessarily the same type and no conversion is performed. 否则,如果T
是值类型,则转换将作为装箱转换执行。Otherwise, ifT
is a value type, the conversion is executed as a boxing conversion. 否则,转换将作为隐式引用转换或标识转换执行。Otherwise, the conversion is executed as an implicit reference conversion or identity conversion. - 从 null 文本到
T
,已知为T
引用类型。From the null literal toT
, providedT
is known to be a reference type. T
向引用类型(I
如果它具有到引用类型的隐式转换S0
和到的S0
标识转换)S
。FromT
to a reference typeI
if it has an implicit conversion to a reference typeS0
andS0
has an identity conversion toS
. 在运行时,转换的执行方式与转换到的方式相同S0
。At run-time the conversion is executed the same way as the conversion toS0
.- 从
T
到接口类型I
(如果它具有到接口或委托类型的隐式转换I0
)并且可以转换为I0
I
(方差转换) 。FromT
to an interface typeI
if it has an implicit conversion to an interface or delegate typeI0
andI0
is variance-convertible toI
(Variance conversion). 在运行时,如果T
是值类型,则转换将作为装箱转换执行。At run-time, ifT
is a value type, the conversion is executed as a boxing conversion. 否则,转换将作为隐式引用转换或标识转换执行。Otherwise, the conversion is executed as an implicit reference conversion or identity conversion.
如果 T
已知 (类型参数约束) 为引用类型,则上述转换全都归类为隐式引用转换 (隐式引用转换) 。If T
is known to be a reference type (Type parameter constraints), the conversions above are all classified as implicit reference conversions (Implicit reference conversions). 如果 T
不知道是引用类型,上面的转换归类为装箱转换 (装箱转换) 。If T
is not known to be a reference type, the conversions above are classified as boxing conversions (Boxing conversions).
用户定义的隐式转换User-defined implicit conversions
用户定义的隐式转换包括一个可选的标准隐式转换,然后执行用户定义的隐式转换运算符,然后执行另一个可选的标准隐式转换。A user-defined implicit conversion consists of an optional standard implicit conversion, followed by execution of a user-defined implicit conversion operator, followed by another optional standard implicit conversion. 用于评估用户定义的隐式转换的确切规则在 处理用户定义的隐式转换中进行了介绍。The exact rules for evaluating user-defined implicit conversions are described in Processing of user-defined implicit conversions.
匿名函数转换和方法组转换Anonymous function conversions and method group conversions
匿名函数和方法组本身没有类型,但可能会隐式转换为委托类型或表达式树类型。Anonymous functions and method groups do not have types in and of themselves, but may be implicitly converted to delegate types or expression tree types. 匿名函数转换和方法组转换中的方法组转换更详细地介绍了匿名函数转换。Anonymous function conversions are described in more detail in Anonymous function conversions and method group conversions in Method group conversions.
显式转换Explicit conversions
以下转换归类为显式转换:The following conversions are classified as explicit conversions:
- 所有隐式转换。All implicit conversions.
- 显式数值转换。Explicit numeric conversions.
- 显式枚举转换。Explicit enumeration conversions.
- 可以为 null 的显式转换。Explicit nullable conversions.
- 显式引用转换。Explicit reference conversions.
- 显式接口转换。Explicit interface conversions.
- 取消装箱转换。Unboxing conversions.
- 显式动态转换Explicit dynamic conversions
- 用户定义的显式转换。User-defined explicit conversions.
显式转换可在转换表达式 () 转换表达式 中发生。Explicit conversions can occur in cast expressions (Cast expressions).
显式转换集包括所有隐式转换。The set of explicit conversions includes all implicit conversions. 这意味着允许冗余强制转换表达式。This means that redundant cast expressions are allowed.
不是隐式转换的显式转换是转换,这种转换不能始终成功、已知的转换可能会丢失信息,并且跨类型的域转换的类型充分不同,以确保显式表示法。The explicit conversions that are not implicit conversions are conversions that cannot be proven to always succeed, conversions that are known to possibly lose information, and conversions across domains of types sufficiently different to merit explicit notation.
显式数值转换Explicit numeric conversions
显式数值转换是指从 numeric_type 到另一个 numeric_type 的转换, (隐式 数值转换) 尚不存在:The explicit numeric conversions are the conversions from a numeric_type to another numeric_type for which an implicit numeric conversion (Implicit numeric conversions) does not already exist:
- 从
sbyte
到byte
、、、ushort
uint
ulong
或char
。Fromsbyte
tobyte
,ushort
,uint
,ulong
, orchar
. - 从
byte
到sbyte
和char
。Frombyte
tosbyte
andchar
. - 从
short
到、、、、sbyte
byte
ushort
uint
ulong
或char
。Fromshort
tosbyte
,byte
,ushort
,uint
,ulong
, orchar
. - 从
ushort
到sbyte
、byte
、short
或char
。Fromushort
tosbyte
,byte
,short
, orchar
. - 从到、、、、、
int
sbyte
byte
short
ushort
uint
ulong
或char
。Fromint
tosbyte
,byte
,short
,ushort
,uint
,ulong
, orchar
. - 从
uint
到、、、、sbyte
byte
short
ushort
int
或char
。Fromuint
tosbyte
,byte
,short
,ushort
,int
, orchar
. - 从到、、、、、、
long
sbyte
byte
short
ushort
int
uint
ulong
或char
。Fromlong
tosbyte
,byte
,short
,ushort
,int
,uint
,ulong
, orchar
. - 从到、、、、、、
ulong
sbyte
byte
short
ushort
int
uint
long
或char
。Fromulong
tosbyte
,byte
,short
,ushort
,int
,uint
,long
, orchar
. - 从
char
到sbyte
、byte
或short
。Fromchar
tosbyte
,byte
, orshort
. - 从到、、、、、、、、
float
sbyte
byte
short
ushort
int
uint
long
ulong
char
或decimal
。Fromfloat
tosbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
, ordecimal
. - 从到、、、、、、、、、
double
sbyte
byte
short
ushort
int
uint
long
ulong
char
float
或decimal
。Fromdouble
tosbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
, ordecimal
. - 从到、、、、、、、、、
decimal
sbyte
byte
short
ushort
int
uint
long
ulong
char
float
或double
。Fromdecimal
tosbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
, ordouble
.
由于显式转换包括所有隐式和显式的数值转换,因此始终可以使用强制转换表达式 (强制转换) 表达式将任何 numeric_type 转换为任何其他 numeric_type 。Because the explicit conversions include all implicit and explicit numeric conversions, it is always possible to convert from any numeric_type to any other numeric_type using a cast expression (Cast expressions).
显式数值转换可能会丢失信息,或可能导致引发异常。The explicit numeric conversions possibly lose information or possibly cause exceptions to be thrown. 显式数值转换的处理方式如下:An explicit numeric conversion is processed as follows:
- 对于从整型转换为另一整型类型的转换,该处理依赖于溢出检查上下文 (已检查和未检查的运算符) 发生转换的:For a conversion from an integral type to another integral type, the processing depends on the overflow checking context (The checked and unchecked operators) in which the conversion takes place:
- 在
checked
上下文中,如果源操作数的值在目标类型的范围内,则转换成功; 但System.OverflowException
如果源操作数的值超出了目标类型的范围,则会引发。In achecked
context, the conversion succeeds if the value of the source operand is within the range of the destination type, but throws aSystem.OverflowException
if the value of the source operand is outside the range of the destination type. - 在
unchecked
上下文中,转换始终成功,并按如下所示继续。In anunchecked
context, the conversion always succeeds, and proceeds as follows.- 如果源类型大于目标类型,则通过放弃其“额外”最高有效位来截断源值。If the source type is larger than the destination type, then the source value is truncated by discarding its "extra" most significant bits. 结果会被视为目标类型的值。The result is then treated as a value of the destination type.
- 如果源类型小于目标类型,则源值是符号扩展或零扩展,以使其与目标类型的大小相同。If the source type is smaller than the destination type, then the source value is either sign-extended or zero-extended so that it is the same size as the destination type. 如果源类型带符号,则是符号扩展;如果源类型是无符号的,则是零扩展。Sign-extension is used if the source type is signed; zero-extension is used if the source type is unsigned. 结果会被视为目标类型的值。The result is then treated as a value of the destination type.
- 如果源类型与目标类型的大小相同,则源值将被视为目标类型的值。If the source type is the same size as the destination type, then the source value is treated as a value of the destination type.
- 在
- 对于从
decimal
到整数类型的转换,源值向零舍入到最接近的整数值,并且此整数值将成为转换的结果。For a conversion fromdecimal
to an integral type, the source value is rounded towards zero to the nearest integral value, and this integral value becomes the result of the conversion. 如果生成的整数值超出了目标类型的范围,System.OverflowException
则会引发。If the resulting integral value is outside the range of the destination type, aSystem.OverflowException
is thrown. - 对于从
float
或double
到整型类型的转换,处理操作依赖于溢出检查上下文 (已检查和未检查的运算符) 发生转换的:For a conversion fromfloat
ordouble
to an integral type, the processing depends on the overflow checking context (The checked and unchecked operators) in which the conversion takes place:- 在
checked
上下文中,转换过程如下所示:In achecked
context, the conversion proceeds as follows:- 如果操作数的值为 NaN 或无穷大,则
System.OverflowException
会引发。If the value of the operand is NaN or infinite, aSystem.OverflowException
is thrown. - 否则,源操作数向零舍入到最接近的整数值。Otherwise, the source operand is rounded towards zero to the nearest integral value. 如果此整数值在目标类型的范围内,则此值为转换的结果。If this integral value is within the range of the destination type then this value is the result of the conversion.
- 否则,将会引发
System.OverflowException
。Otherwise, aSystem.OverflowException
is thrown.
- 如果操作数的值为 NaN 或无穷大,则
- 在
unchecked
上下文中,转换始终成功,并按如下所示继续。In anunchecked
context, the conversion always succeeds, and proceeds as follows.- 如果操作数的值为 NaN 或无穷大,则转换的结果是目标类型的未指定值。If the value of the operand is NaN or infinite, the result of the conversion is an unspecified value of the destination type.
- 否则,源操作数向零舍入到最接近的整数值。Otherwise, the source operand is rounded towards zero to the nearest integral value. 如果此整数值在目标类型的范围内,则此值为转换的结果。If this integral value is within the range of the destination type then this value is the result of the conversion.
- 否则,转换的结果是目标类型的未指定值。Otherwise, the result of the conversion is an unspecified value of the destination type.
- 在
- 对于从到的
double
转换float
,此double
值舍入为最接近的float
值。For a conversion fromdouble
tofloat
, thedouble
value is rounded to the nearestfloat
value. 如果double
值太小而无法表示为float
,则结果将变为正零或负零。If thedouble
value is too small to represent as afloat
, the result becomes positive zero or negative zero. 如果double
值太大而无法表示为float
,则结果将变为正无穷或负无穷。If thedouble
value is too large to represent as afloat
, the result becomes positive infinity or negative infinity. 如果double
该值为 nan,则结果也为 nan。If thedouble
value is NaN, the result is also NaN. - 对于从
float
或到的double
转换decimal
,将源值转换为decimal
表示形式,并在第28位小数后舍入为最接近的数(如果需要 (decimal 类型) 。For a conversion fromfloat
ordouble
todecimal
, the source value is converted todecimal
representation and rounded to the nearest number after the 28th decimal place if required (The decimal type). 如果源值太小而无法表示为decimal
,则结果将变为零。If the source value is too small to represent as adecimal
, the result becomes zero. 如果源值为 NaN、无限大或太大而无法表示为decimal
,System.OverflowException
则会引发。If the source value is NaN, infinity, or too large to represent as adecimal
, aSystem.OverflowException
is thrown. - 对于从
decimal
到或的float
转换double
,将decimal
值舍入为最接近double
的float
值或值。For a conversion fromdecimal
tofloat
ordouble
, thedecimal
value is rounded to the nearestdouble
orfloat
value. 虽然这种转换可能会丢失精度,但它永远不会引发异常。While this conversion may lose precision, it never causes an exception to be thrown.
显式枚举转换Explicit enumeration conversions
显式枚举转换为:The explicit enumeration conversions are:
- 从
sbyte
、byte
、、、、、、、、、short
ushort
int
uint
long
ulong
char
float
double
或decimal
到任何 enum_type。Fromsbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
, ordecimal
to any enum_type. - 从任何 enum_type 到、、、、、、、、、、
sbyte
byte
short
ushort
int
uint
long
ulong
char
float
double
或decimal
。From any enum_type tosbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
, ordecimal
. - 从任何 enum_type 到任何其他 enum_type。From any enum_type to any other enum_type.
处理两种类型之间的显式枚举转换的方式是将任何参与的 enum_type 视为 enum_type 的基础类型,然后在生成的类型之间执行隐式或显式数字转换。An explicit enumeration conversion between two types is processed by treating any participating enum_type as the underlying type of that enum_type, and then performing an implicit or explicit numeric conversion between the resulting types. 例如,假设有一个 E
具有和基础类型的 enum_type,则从到的显式数字转换 int
会将从到的转换 E
byte
作为显式数字转换处理 (从到的) 显式数字转换 int
byte
,并将从) 到的 byte
E
隐式数值转换作为 (隐 byte
int
式数值转换处理。For example, given an enum_type E
with and underlying type of int
, a conversion from E
to byte
is processed as an explicit numeric conversion (Explicit numeric conversions) from int
to byte
, and a conversion from byte
to E
is processed as an implicit numeric conversion (Implicit numeric conversions) from byte
to int
.
显式可为空转换Explicit nullable conversions
显式可以为 null 的转换 允许对不可以为 null 的值类型进行操作的预定义显式转换也可用于这些类型的可以为 null 的形式。Explicit nullable conversions permit predefined explicit conversions that operate on non-nullable value types to also be used with nullable forms of those types. 对于从不可为 null 的值类型转换为不可为 null 的值类型的每个预定义的显式转换 S
T
(标识转换、 隐式数值转换、 隐式枚举转换、 显式数字转换和 显式枚举转换) ,可以为 null 的转换存在:For each of the predefined explicit conversions that convert from a non-nullable value type S
to a non-nullable value type T
(Identity conversion, Implicit numeric conversions, Implicit enumeration conversions, Explicit numeric conversions, and Explicit enumeration conversions), the following nullable conversions exist:
- 从到的显式
S?
转换T?
。An explicit conversion fromS?
toT?
. - 从到的显式
S
转换T?
。An explicit conversion fromS
toT?
. - 从到的显式
S?
转换T
。An explicit conversion fromS?
toT
.
基于从到的基础转换计算可以为 null 的转换的 S
T
过程如下所示:Evaluation of a nullable conversion based on an underlying conversion from S
to T
proceeds as follows:
- 如果可以为 null 的转换从
S?
到T?
:If the nullable conversion is fromS?
toT?
:- 如果源值为 null (
HasValue
属性为 false) ,则结果为类型的 null 值T?
。If the source value is null (HasValue
property is false), the result is the null value of typeT?
. - 否则,转换将作为从到的解包进行计算
S?
S
,后跟从到的S
转换T
,后跟从到的换行T
T?
。Otherwise, the conversion is evaluated as an unwrapping fromS?
toS
, followed by the underlying conversion fromS
toT
, followed by a wrapping fromT
toT?
.
- 如果源值为 null (
- 如果可以为 null 的转换从
S
到T?
,则会将转换计算为从到的基础转换,S
并将从到T
的换行T
T?
。If the nullable conversion is fromS
toT?
, the conversion is evaluated as the underlying conversion fromS
toT
followed by a wrapping fromT
toT?
. - 如果从到的可为 null 的转换为
S?
T
,则会将转换计算为从到的解包,S?
S
后跟从到的基础转换S
T
。If the nullable conversion is fromS?
toT
, the conversion is evaluated as an unwrapping fromS?
toS
followed by the underlying conversion fromS
toT
.
请注意,如果值为,则对可以为 null 的值进行解包的尝试将引发异常 null
。Note that an attempt to unwrap a nullable value will throw an exception if the value is null
.
显式引用转换Explicit reference conversions
显式引用转换为:The explicit reference conversions are:
- 从
object
和dynamic
到任何其他 reference_type。Fromobject
anddynamic
to any other reference_type. - 从任何 class_type
S
到任何 class_typeT
,提供的S
是的基类T
。From any class_typeS
to any class_typeT
, providedS
is a base class ofT
. - 从任何 class_type
S
到任何 interface_typeT
,提供S
的不是密封的,并且不S
会实现T
。From any class_typeS
to any interface_typeT
, providedS
is not sealed and providedS
does not implementT
. - 从任何 interface_type
S
到任何 class_typeT
T
均未密封或未提供T
实现S
。From any interface_typeS
to any class_typeT
, providedT
is not sealed or providedT
implementsS
. - 从任何 interface_type
S
到任何 interface_typeT
,提供S
的不是从派生的T
。From any interface_typeS
to any interface_typeT
, providedS
is not derived fromT
. - 在 array_type 具有元素类型的 array_type 中
S
,如果SE
T
TE
满足以下所有条件:From an array_typeS
with an element typeSE
to an array_typeT
with an element typeTE
, provided all of the following are true:S
和T
仅因元素类型而异。S
andT
differ only in element type. 换言之,S
和T
具有相同的维数。In other words,S
andT
have the same number of dimensions.SE
和TE
都是 reference_type。BothSE
andTE
are reference_type s.- 存在从到的显式引用
SE
转换TE
。An explicit reference conversion exists fromSE
toTE
.
- 从
System.Array
及其实现的接口到任何 array_type。FromSystem.Array
and the interfaces it implements to any array_type. - 从一维数组类型
S[]
到System.Collections.Generic.IList<T>
及其基接口,前提是存在从到的显式引用转换S
T
。From a single-dimensional array typeS[]
toSystem.Collections.Generic.IList<T>
and its base interfaces, provided that there is an explicit reference conversion fromS
toT
. - 从
System.Collections.Generic.IList<S>
及其基接口到一维数组类型T[]
,前提是存在从到的显式标识或引用转换S
T
。FromSystem.Collections.Generic.IList<S>
and its base interfaces to a single-dimensional array typeT[]
, provided that there is an explicit identity or reference conversion fromS
toT
. - 从
System.Delegate
及其实现的接口到任何 delegate_type。FromSystem.Delegate
and the interfaces it implements to any delegate_type. - 如果引用类型
T
具有到引用类型的显式引用转换T0
并且T0
具有标识转换,则从引用类型转换为引用类型T
。From a reference type to a reference typeT
if it has an explicit reference conversion to a reference typeT0
andT0
has an identity conversionT
. - 如果引用类型
T
具有到接口或委托类型的显式引用转换,则从引用类型转换为接口或委托类型T0
,或者可以转换为 (方差T0
T
T
T0
转换) 的变体。From a reference type to an interface or delegate typeT
if it has an explicit reference conversion to an interface or delegate typeT0
and eitherT0
is variance-convertible toT
orT
is variance-convertible toT0
(Variance conversion). - 从
D<S1...Sn>
到,D<T1...Tn>
其中D<X1...Xn>
是泛型委托类型,与D<S1...Sn>
D<T1...Tn>
以下类型的每个类型参数均不兼容或不相同Xi
D
:FromD<S1...Sn>
toD<T1...Tn>
whereD<X1...Xn>
is a generic delegate type,D<S1...Sn>
is not compatible with or identical toD<T1...Tn>
, and for each type parameterXi
ofD
the following holds:- 如果
Xi
是固定的,则与Si
相同Ti
。IfXi
is invariant, thenSi
is identical toTi
. - 如果
Xi
是协变的,则存在隐式或显式标识或从到的引用转换Si
Ti
。IfXi
is covariant, then there is an implicit or explicit identity or reference conversion fromSi
toTi
. - 如果
Xi
为逆变,则Si
和Ti
都是相同或同时为这两个引用类型。IfXi
is contravariant, thenSi
andTi
are either identical or both reference types.
- 如果
- 涉及称为引用类型的类型参数的显式转换。Explicit conversions involving type parameters that are known to be reference types. 有关涉及类型参数的显式转换的详细信息,请参阅 涉及类型参数的显式转换。For more details on explicit conversions involving type parameters, see Explicit conversions involving type parameters.
显式引用转换是需要运行时检查以确保它们正确的引用类型之间的转换。The explicit reference conversions are those conversions between reference-types that require run-time checks to ensure they are correct.
若要在运行时成功进行显式引用转换,源操作数的值必须为 null
,或者源操作数引用的对象的实际类型必须是可通过隐式引用转换转换为目标类型的类型, (隐式引用 转换) 或装箱转换 (装箱 转换) 。For an explicit reference conversion to succeed at run-time, the value of the source operand must be null
, or the actual type of the object referenced by the source operand must be a type that can be converted to the destination type by an implicit reference conversion (Implicit reference conversions) or boxing conversion (Boxing conversions). 如果显式引用转换失败, System.InvalidCastException
将引发。If an explicit reference conversion fails, a System.InvalidCastException
is thrown.
引用转换、隐式或显式转换决不会更改正在转换的对象的引用标识。Reference conversions, implicit or explicit, never change the referential identity of the object being converted. 换言之,虽然引用转换可以更改引用的类型,但它不会更改引用的对象的类型或值。In other words, while a reference conversion may change the type of the reference, it never changes the type or value of the object being referred to.
取消装箱转换Unboxing conversions
取消装箱转换允许将引用类型显式转换为 value_type。An unboxing conversion permits a reference type to be explicitly converted to a value_type. 从类型 object
dynamic
和 System.ValueType
任何 non_nullable_value_type,以及从任何 interface_type 到实现 interface_type 的任何 non_nullable_value_type 的取消装箱转换。An unboxing conversion exists from the types object
, dynamic
and System.ValueType
to any non_nullable_value_type, and from any interface_type to any non_nullable_value_type that implements the interface_type. 此外 System.Enum
,可以将类型取消装箱为任意 enum_type。Furthermore type System.Enum
can be unboxed to any enum_type.
如果从引用类型到 nullable_type 的基础 non_nullable_value_type 的取消装箱转换存在,则取消装箱转换将从引用类型转换为 nullable_type 。An unboxing conversion exists from a reference type to a nullable_type if an unboxing conversion exists from the reference type to the underlying non_nullable_value_type of the nullable_type.
如果值类型 S
I
具有从接口类型的取消装箱转换 I0
,并且其 I0
标识转换为,则值类型会从接口类型进行取消装箱转换 I
。A value type S
has an unboxing conversion from an interface type I
if it has an unboxing conversion from an interface type I0
and I0
has an identity conversion to I
.
如果某个值类型 S
I
具有从接口或委托类型的取消装箱转换,并且该类型的变体转换为 I0
I0
I
I
I0
(方差转换) ,则它会从接口类型进行取消装箱转换。A value type S
has an unboxing conversion from an interface type I
if it has an unboxing conversion from an interface or delegate type I0
and either I0
is variance-convertible to I
or I
is variance-convertible to I0
(Variance conversion).
取消装箱操作包括:首先检查对象实例是否是给定 value_type 的装箱值,然后将值复制到该实例之外。An unboxing operation consists of first checking that the object instance is a boxed value of the given value_type, and then copying the value out of the instance. 取消装箱对 nullable_type 的空引用将生成 nullable_type 的 null 值。Unboxing a null reference to a nullable_type produces the null value of the nullable_type. 结构可以从类型取消装箱 System.ValueType
,因为这是所有结构的基类 (继承) 。A struct can be unboxed from the type System.ValueType
, since that is a base class for all structs (Inheritance).
取消装箱转换中进一步介绍 了取消装箱转换。Unboxing conversions are described further in Unboxing conversions.
显式动态转换Explicit dynamic conversions
存在从类型为的表达式 dynamic
到任何类型的显式动态转换 T
。An explicit dynamic conversion exists from an expression of type dynamic
to any type T
. 转换是动态绑定 (动态绑定) ,这意味着将在运行时从表达式的运行时类型中查找显式转换 T
。The conversion is dynamically bound (Dynamic binding), which means that an explicit conversion will be sought at run-time from the run-time type of the expression to T
. 如果未找到任何转换,则会引发运行时异常。If no conversion is found, a run-time exception is thrown.
如果不需要转换的动态绑定,则可以先将该表达式转换为 object
,然后再转换为所需的类型。If dynamic binding of the conversion is not desired, the expression can be first converted to object
, and then to the desired type.
假定定义了下面的类:Assume the following class is defined:
class C
{
int i;
public C(int i) { this.i = i; }
public static explicit operator C(string s)
{
return new C(int.Parse(s));
}
}
下面的示例阐释了显式动态转换:The following example illustrates explicit dynamic conversions:
object o = "1";
dynamic d = "2";
var c1 = (C)o; // Compiles, but explicit reference conversion fails
var c2 = (C)d; // Compiles and user defined conversion succeeds
在编译时,将转换为的最佳转换为 o
C
显式引用转换。The best conversion of o
to C
is found at compile-time to be an explicit reference conversion. 这会在运行时失败,因为 "1"
事实上并不是 C
。This fails at run-time, because "1"
is not in fact a C
. 但是,将转换为,以 d
C
显式动态转换为运行时,将在其中找到用户定义的运行时类型到的转换 d
-- string
C
,并成功。The conversion of d
to C
however, as an explicit dynamic conversion, is suspended to run-time, where a user defined conversion from the run-time type of d
-- string
-- to C
is found, and succeeds.
涉及类型参数的显式转换Explicit conversions involving type parameters
给定类型参数存在以下显式转换 T
:The following explicit conversions exist for a given type parameter T
:
- 从的有效基类
C
T
,到的T
任何基类C
T
。From the effective base classC
ofT
toT
and from any base class ofC
toT
. 在运行时,如果T
是值类型,则转换将作为取消装箱转换执行。At run-time, ifT
is a value type, the conversion is executed as an unboxing conversion. 否则,转换将作为显式引用转换或标识转换执行。Otherwise, the conversion is executed as an explicit reference conversion or identity conversion. - 从任何接口类型到
T
。From any interface type toT
. 在运行时,如果T
是值类型,则转换将作为取消装箱转换执行。At run-time, ifT
is a value type, the conversion is executed as an unboxing conversion. 否则,转换将作为显式引用转换或标识转换执行。Otherwise, the conversion is executed as an explicit reference conversion or identity conversion. T
I
如果尚未从到的隐式转换,则从到任何T
interface_typeI
。FromT
to any interface_typeI
provided there is not already an implicit conversion fromT
toI
. 在运行时,如果T
是值类型,则转换将作为装箱转换执行,后跟显式引用转换。At run-time, ifT
is a value type, the conversion is executed as a boxing conversion followed by an explicit reference conversion. 否则,转换将作为显式引用转换或标识转换执行。Otherwise, the conversion is executed as an explicit reference conversion or identity conversion.- 从类型参数
U
到T
,前提条件T
取决于U
) (类型参数约束 。From a type parameterU
toT
, providedT
depends onU
(Type parameter constraints). 在运行时,如果U
是值类型,则和的T
U
类型必须相同,并且不执行任何转换。At run-time, ifU
is a value type, thenT
andU
are necessarily the same type and no conversion is performed. 否则,如果T
是值类型,则转换将作为取消装箱转换执行。Otherwise, ifT
is a value type, the conversion is executed as an unboxing conversion. 否则,转换将作为显式引用转换或标识转换执行。Otherwise, the conversion is executed as an explicit reference conversion or identity conversion.
如果 T
已知为引用类型,则上述转换均分类为显式引用转换 () 的 显式引用转换 。If T
is known to be a reference type, the conversions above are all classified as explicit reference conversions (Explicit reference conversions). 如果 T
未知类型为引用类型,则上述转换归类为取消装箱转换 (取消装箱转换) 。If T
is not known to be a reference type, the conversions above are classified as unboxing conversions (Unboxing conversions).
以上规则不允许从不受约束的类型形参直接转换为非接口类型,这可能会令人吃惊。The above rules do not permit a direct explicit conversion from an unconstrained type parameter to a non-interface type, which might be surprising. 此规则的原因是为了防止混淆并使此类转换的语义清晰。The reason for this rule is to prevent confusion and make the semantics of such conversions clear. 例如,请考虑以下声明:For example, consider the following declaration:
class X<T>
{
public static long F(T t) {
return (long)t; // Error
}
}
如果允许将的直接显式转换 t
为 int
,则很可能会出现这样的情况 X<int>.F(7)
7L
。If the direct explicit conversion of t
to int
were permitted, one might easily expect that X<int>.F(7)
would return 7L
. 但是,它不会这样,因为仅当已知类型在绑定时是数字时才考虑标准数字转换。However, it would not, because the standard numeric conversions are only considered when the types are known to be numeric at binding-time. 为了使语义清晰明了,必须改为编写以上示例:In order to make the semantics clear, the above example must instead be written:
class X<T>
{
public static long F(T t) {
return (long)(object)t; // Ok, but will only work when T is long
}
}
此代码现在将进行编译,但执行 X<int>.F(7)
会在运行时引发异常,因为装箱 int
无法直接转换为 long
。This code will now compile but executing X<int>.F(7)
would then throw an exception at run-time, since a boxed int
cannot be converted directly to a long
.
用户定义的显式转换User-defined explicit conversions
用户定义的显式转换包含一个可选的标准显式转换,然后执行用户定义的隐式或显式转换运算符,然后执行另一个可选的标准显式转换。A user-defined explicit conversion consists of an optional standard explicit conversion, followed by execution of a user-defined implicit or explicit conversion operator, followed by another optional standard explicit conversion. 用于评估用户定义的显式转换的确切规则在 处理用户定义的显式转换中进行了介绍。The exact rules for evaluating user-defined explicit conversions are described in Processing of user-defined explicit conversions.
标准转换Standard conversions
标准转换是那些预定义的转换,这些转换可作为用户定义的转换的一部分出现。The standard conversions are those pre-defined conversions that can occur as part of a user-defined conversion.
标准隐式转换Standard implicit conversions
以下隐式转换归类为标准隐式转换:The following implicit conversions are classified as standard implicit conversions:
- 标识转换 (标识转换) Identity conversions (Identity conversion)
- 隐式数值转换 (隐式数值转换) Implicit numeric conversions (Implicit numeric conversions)
- 隐式可为 null 转换 (隐式可为 null 转换) Implicit nullable conversions (Implicit nullable conversions)
- 隐 式引用转换 (隐 式引用转换) Implicit reference conversions (Implicit reference conversions)
- 装箱转换 (装箱转换) Boxing conversions (Boxing conversions)
- 隐式常量表达式转换 (隐式常量表达式转换) Implicit constant expression conversions (Implicit constant expression conversions)
- 涉及类型参数的隐式转换 (涉及类型参数的隐式转换) Implicit conversions involving type parameters (Implicit conversions involving type parameters)
标准隐式转换专门排除用户定义的隐式转换。The standard implicit conversions specifically exclude user-defined implicit conversions.
标准显式转换Standard explicit conversions
标准显式转换均为标准隐式转换,以及与之相反的标准隐式转换的显式转换的子集。The standard explicit conversions are all standard implicit conversions plus the subset of the explicit conversions for which an opposite standard implicit conversion exists. 换言之,如果存在从类型到类型的标准隐式转换 A
B
,则从类型 A
到类型 B
以及从类型到类型的标准显式转换 B
A
。In other words, if a standard implicit conversion exists from a type A
to a type B
, then a standard explicit conversion exists from type A
to type B
and from type B
to type A
.
用户定义的转换User-defined conversions
C # 允许使用 用户定义的转换 来扩充预定义的隐式和显式转换。C# allows the pre-defined implicit and explicit conversions to be augmented by user-defined conversions. 用户定义的转换是通过在类和结构类型中 (转换运算符) 声明转换运算符引入的。User-defined conversions are introduced by declaring conversion operators (Conversion operators) in class and struct types.
允许的用户定义的转换Permitted user-defined conversions
C # 只允许声明某些用户定义的转换。C# permits only certain user-defined conversions to be declared. 特别是,不能重新定义已存在的隐式或显式转换。In particular, it is not possible to redefine an already existing implicit or explicit conversion.
对于给定的源类型 S
和目标类型 T
,如果 S
或 T
是可以为 null 的类型,则让 S0
和 T0
引用它们的基础类型,否则, S0
并 T0
S
T
分别为和。For a given source type S
and target type T
, if S
or T
are nullable types, let S0
and T0
refer to their underlying types, otherwise S0
and T0
are equal to S
and T
respectively. S
T
仅当满足以下所有条件时,才允许类或结构声明从源类型到目标类型的转换:A class or struct is permitted to declare a conversion from a source type S
to a target type T
only if all of the following are true:
S0
和T0
是不同的类型。S0
andT0
are different types.S0
或T0
是发生运算符声明的类或结构类型。EitherS0
orT0
is the class or struct type in which the operator declaration takes place.S0
和T0
都不是 interface_type。NeitherS0
norT0
is an interface_type.- 如果不包括用户定义的转换,则从到的转换不存在
S
T
T
S
。Excluding user-defined conversions, a conversion does not exist fromS
toT
or fromT
toS
.
适用于用户定义的转换的限制将在 转换运算符中进一步讨论。The restrictions that apply to user-defined conversions are discussed further in Conversion operators.
提升的转换运算符Lifted conversion operators
给定用户定义的转换运算符,该运算符将不可以为 null 的值类型转换 S
为不可为 null 的值类型 T
,并且存在将从转换为的 提升转换运算符 S?
T?
。Given a user-defined conversion operator that converts from a non-nullable value type S
to a non-nullable value type T
, a lifted conversion operator exists that converts from S?
to T?
. 此提升转换运算符执行从到的解包,然后执行从到的 S?
S
用户定义的转换 S
T
,后跟从到的换行 T
T?
,只不过空值 S?
直接转换为 null 值 T?
。This lifted conversion operator performs an unwrapping from S?
to S
followed by the user-defined conversion from S
to T
followed by a wrapping from T
to T?
, except that a null valued S?
converts directly to a null valued T?
.
提升的转换运算符与其基础用户定义转换运算符具有相同的隐式或显式分类。A lifted conversion operator has the same implicit or explicit classification as its underlying user-defined conversion operator. "用户定义的转换" 一词适用于用户定义的转换运算符和提升的转换运算符。The term "user-defined conversion" applies to the use of both user-defined and lifted conversion operators.
计算用户定义的转换Evaluation of user-defined conversions
用户定义的转换将其类型(称为 源类型 _)的值转换为另一种类型,称为 _目标类型*。A user-defined conversion converts a value from its type, called the source type _, to another type, called the _target type*. 计算用户定义的转换中心,查找特定源和目标类型的 _ 最具体 的 * 用户定义转换运算符。Evaluation of a user-defined conversion centers on finding the _ most specific* user-defined conversion operator for the particular source and target types. 此确定分为几个步骤:This determination is broken into several steps:
- 查找要将用户定义的转换运算符视为其中的一组类和结构。Finding the set of classes and structs from which user-defined conversion operators will be considered. 此集由源类型及其基类和目标类型及其基类 (,这些隐式假设只有类和结构可以声明用户定义的运算符,并且非类类型没有基类) 。This set consists of the source type and its base classes and the target type and its base classes (with the implicit assumptions that only classes and structs can declare user-defined operators, and that non-class types have no base classes). 对于此步骤,如果源类型或目标类型为 nullable_type,则改为使用它们的基础类型。For the purposes of this step, if either the source or target type is a nullable_type, their underlying type is used instead.
- 从该类型集中确定哪些用户定义的转换运算符适用。From that set of types, determining which user-defined and lifted conversion operators are applicable. 要使转换运算符适用,必须可以执行标准转换 (标准 转换) 从源类型转换为运算符的操作数类型,并且必须能够执行从运算符的结果类型到目标类型的标准转换操作。For a conversion operator to be applicable, it must be possible to perform a standard conversion (Standard conversions) from the source type to the operand type of the operator, and it must be possible to perform a standard conversion from the result type of the operator to the target type.
- 从一组适用的用户定义的运算符,确定哪个运算符明确是最具体的。From the set of applicable user-defined operators, determining which operator is unambiguously the most specific. 一般来说,最特定的运算符是操作数类型与源类型 "最接近" 的运算符,其结果类型与目标类型 "最近"。In general terms, the most specific operator is the operator whose operand type is "closest" to the source type and whose result type is "closest" to the target type. 用户定义的转换运算符优先于提升转换运算符。User-defined conversion operators are preferred over lifted conversion operators. 以下部分定义了用于建立最具体的用户定义转换运算符的确切规则。The exact rules for establishing the most specific user-defined conversion operator are defined in the following sections.
确定了最特定的用户定义转换运算符后,用户定义的转换的实际执行操作包括多达三个步骤:Once a most specific user-defined conversion operator has been identified, the actual execution of the user-defined conversion involves up to three steps:
- 首先,如果需要,执行从源类型到用户定义或提升的转换运算符的操作数类型的标准转换。First, if required, performing a standard conversion from the source type to the operand type of the user-defined or lifted conversion operator.
- 接下来,调用用户定义或提升的转换运算符来执行转换。Next, invoking the user-defined or lifted conversion operator to perform the conversion.
- 最后,如果需要,执行从用户定义转换运算符的结果类型到目标类型的标准转换。Finally, if required, performing a standard conversion from the result type of the user-defined or lifted conversion operator to the target type.
用户定义的转换的计算从不涉及多个用户定义的转换运算符或提升的转换运算符。Evaluation of a user-defined conversion never involves more than one user-defined or lifted conversion operator. 换句话说,从类型到类型的转换 S
T
从不首先执行从到的用户定义的转换 S
X
,然后执行从到的用户定义的转换 X
T
。In other words, a conversion from type S
to type T
will never first execute a user-defined conversion from S
to X
and then execute a user-defined conversion from X
to T
.
以下各节提供了用户定义的隐式或显式转换的确切计算定义。Exact definitions of evaluation of user-defined implicit or explicit conversions are given in the following sections. 定义使用以下术语:The definitions make use of the following terms:
- 如果标准隐式转换 (从类型到类型的标准 隐式转换)
A
B
,并且和都不A
B
interface_type,则称为A
*包含 _B
,并B
被称为 _ 包含 *A
。If a standard implicit conversion (Standard implicit conversions) exists from a typeA
to a typeB
, and if neitherA
norB
are interface_type s, thenA
is said to be encompassed by _B
, andB
is said to _ encompassA
. - 一组类型中包含的 最大的类型 是一种包含集内所有其他类型的类型。The most encompassing type in a set of types is the one type that encompasses all other types in the set. 如果没有一种类型包含所有其他类型,则该集没有最大的包含类型。If no single type encompasses all other types, then the set has no most encompassing type. 更直观地说,最包含的类型是集中的 "最大" 类型,每个其他类型都可以隐式转换为一种类型。In more intuitive terms, the most encompassing type is the "largest" type in the set—the one type to which each of the other types can be implicitly converted.
- 类型集中 最常被包含的类型 是一种类型,它由集中的所有其他类型所包含。The most encompassed type in a set of types is the one type that is encompassed by all other types in the set. 如果所有其他类型都不包含任何一种类型,则该集不包含大多数被包含的类型。If no single type is encompassed by all other types, then the set has no most encompassed type. 更直观地说,最包含的类型是集中的 "最小" 类型,这种类型可以隐式转换为其他类型。In more intuitive terms, the most encompassed type is the "smallest" type in the set—the one type that can be implicitly converted to each of the other types.
处理用户定义的隐式转换Processing of user-defined implicit conversions
用户定义的从类型到类型的隐式转换的 S
T
处理方式如下:A user-defined implicit conversion from type S
to type T
is processed as follows:
- 确定类型
S0
和T0
。Determine the typesS0
andT0
. 如果S
或T
是可以为 null 的类型,S0
并且T0
是其基础类型,则为; 否则S0
T0
分别为和S
T
。IfS
orT
are nullable types,S0
andT0
are their underlying types, otherwiseS0
andT0
are equal toS
andT
respectively. - 查找类型集,
D
用户定义的转换运算符将从其考虑。Find the set of types,D
, from which user-defined conversion operators will be considered.S0
如果是类或结构) ,则此集由 (组成S0
, (的基类(S0
如果S0
是类) )和T0
((如果T0
是类或结构) )。This set consists ofS0
(ifS0
is a class or struct), the base classes ofS0
(ifS0
is a class), andT0
(ifT0
is a class or struct). - 查找适用的用户定义转换运算符和提升转换运算符集
U
。Find the set of applicable user-defined and lifted conversion operators,U
. 此集由中的类或结构所声明的用户定义的和提升的隐式转换运算符组成,这些类或结构从包含的类型包含在中D
S
T
。This set consists of the user-defined and lifted implicit conversion operators declared by the classes or structs inD
that convert from a type encompassingS
to a type encompassed byT
. 如果U
为空,则不定义转换,并发生编译时错误。IfU
is empty, the conversion is undefined and a compile-time error occurs. - 查找中运算符的最特定源类型
SX
U
:Find the most specific source type,SX
, of the operators inU
:- 如果中的任何运算符
U
S
都为,则SX
为S
。If any of the operators inU
convert fromS
, thenSX
isS
. - 否则,
SX
是中运算符的组合源类型集内包含程度最高的类型U
。Otherwise,SX
is the most encompassed type in the combined set of source types of the operators inU
. 如果找不到完全包含的类型,则转换是不明确的,并发生编译时错误。If exactly one most encompassed type cannot be found, then the conversion is ambiguous and a compile-time error occurs.
- 如果中的任何运算符
- 查找中运算符的最特定目标类型
TX
U
:Find the most specific target type,TX
, of the operators inU
:- 如果中的任何运算符
U
转换为T
,则TX
为T
。If any of the operators inU
convert toT
, thenTX
isT
. - 否则,
TX
是中运算符的组合目标类型集中的最包含的类型U
。Otherwise,TX
is the most encompassing type in the combined set of target types of the operators inU
. 如果找不到完全包含的类型,则转换是不明确的,并发生编译时错误。If exactly one most encompassing type cannot be found, then the conversion is ambiguous and a compile-time error occurs.
- 如果中的任何运算符
- 查找最具体的转换运算符:Find the most specific conversion operator:
- 如果
U
只包含一个从转换为的用户定义的转换SX
运算符TX
,则这是最具体的转换运算符。IfU
contains exactly one user-defined conversion operator that converts fromSX
toTX
, then this is the most specific conversion operator. - 否则,如果
U
只包含一个从转换为的提升转换SX
运算符TX
,则这是最具体的转换运算符。Otherwise, ifU
contains exactly one lifted conversion operator that converts fromSX
toTX
, then this is the most specific conversion operator. - 否则,转换是不明确的,并发生编译时错误。Otherwise, the conversion is ambiguous and a compile-time error occurs.
- 如果
- 最后,应用转换:Finally, apply the conversion:
- 如果不
S
为SX
,则执行从到的标准隐式转换S
SX
。IfS
is notSX
, then a standard implicit conversion fromS
toSX
is performed. - 调用最特定的转换运算符,以将转换
SX
为TX
。The most specific conversion operator is invoked to convert fromSX
toTX
. - 如果不
TX
为T
,则执行从到的标准隐式转换TX
T
。IfTX
is notT
, then a standard implicit conversion fromTX
toT
is performed.
- 如果不
处理用户定义的显式转换Processing of user-defined explicit conversions
用户定义的从类型到类型的显式转换的 S
T
处理方式如下:A user-defined explicit conversion from type S
to type T
is processed as follows:
- 确定类型
S0
和T0
。Determine the typesS0
andT0
. 如果S
或T
是可以为 null 的类型,S0
并且T0
是其基础类型,则为; 否则S0
T0
分别为和S
T
。IfS
orT
are nullable types,S0
andT0
are their underlying types, otherwiseS0
andT0
are equal toS
andT
respectively. - 查找类型集,
D
用户定义的转换运算符将从其考虑。Find the set of types,D
, from which user-defined conversion operators will be considered.S0
如果是类或结构) ,则此集由 (,如果是类S0
或结构、 (的基类(S0
如果是类S0
) )、T0
(ifT0
是类或结构) ,以及 (的基类(T0
如果T0
是类) )。This set consists ofS0
(ifS0
is a class or struct), the base classes ofS0
(ifS0
is a class),T0
(ifT0
is a class or struct), and the base classes ofT0
(ifT0
is a class). - 查找适用的用户定义转换运算符和提升转换运算符集
U
。Find the set of applicable user-defined and lifted conversion operators,U
. 此集由中由的类或结构声明的用户定义的隐式或显式转换运算符,由中的D
类型转换S
为包含或包含的类型T
。This set consists of the user-defined and lifted implicit or explicit conversion operators declared by the classes or structs inD
that convert from a type encompassing or encompassed byS
to a type encompassing or encompassed byT
. 如果U
为空,则不定义转换,并发生编译时错误。IfU
is empty, the conversion is undefined and a compile-time error occurs. - 查找中运算符的最特定源类型
SX
U
:Find the most specific source type,SX
, of the operators inU
:- 如果中的任何运算符
U
S
都为,则SX
为S
。If any of the operators inU
convert fromS
, thenSX
isS
. - 否则,如果中的任何运算符
U
从包含的类型转换S
,则SX
是这些运算符的组合源类型集中包含程度最高的类型。Otherwise, if any of the operators inU
convert from types that encompassS
, thenSX
is the most encompassed type in the combined set of source types of those operators. 如果找不到最能包含的类型,则转换是不明确的,并发生编译时错误。If no most encompassed type can be found, then the conversion is ambiguous and a compile-time error occurs. - 否则,
SX
是中运算符的组合源类型集中的最包含的类型U
。Otherwise,SX
is the most encompassing type in the combined set of source types of the operators inU
. 如果找不到完全包含的类型,则转换是不明确的,并发生编译时错误。If exactly one most encompassing type cannot be found, then the conversion is ambiguous and a compile-time error occurs.
- 如果中的任何运算符
- 查找中运算符的最特定目标类型
TX
U
:Find the most specific target type,TX
, of the operators inU
:- 如果中的任何运算符
U
转换为T
,则TX
为T
。If any of the operators inU
convert toT
, thenTX
isT
. - 否则,如果中的任何运算符
U
转换为所包含的类型,则T
TX
是这些运算符的组合目标类型集中最包含的类型。Otherwise, if any of the operators inU
convert to types that are encompassed byT
, thenTX
is the most encompassing type in the combined set of target types of those operators. 如果找不到完全包含的类型,则转换是不明确的,并发生编译时错误。If exactly one most encompassing type cannot be found, then the conversion is ambiguous and a compile-time error occurs. - 否则,
TX
是中运算符的组合目标类型集中的包含程度最高的类型U
。Otherwise,TX
is the most encompassed type in the combined set of target types of the operators inU
. 如果找不到最能包含的类型,则转换是不明确的,并发生编译时错误。If no most encompassed type can be found, then the conversion is ambiguous and a compile-time error occurs.
- 如果中的任何运算符
- 查找最具体的转换运算符:Find the most specific conversion operator:
- 如果
U
只包含一个从转换为的用户定义的转换SX
运算符TX
,则这是最具体的转换运算符。IfU
contains exactly one user-defined conversion operator that converts fromSX
toTX
, then this is the most specific conversion operator. - 否则,如果
U
只包含一个从转换为的提升转换SX
运算符TX
,则这是最具体的转换运算符。Otherwise, ifU
contains exactly one lifted conversion operator that converts fromSX
toTX
, then this is the most specific conversion operator. - 否则,转换是不明确的,并发生编译时错误。Otherwise, the conversion is ambiguous and a compile-time error occurs.
- 如果
- 最后,应用转换:Finally, apply the conversion:
- 如果不
S
为SX
,则执行从到的标准显式转换S
SX
。IfS
is notSX
, then a standard explicit conversion fromS
toSX
is performed. - 调用最特定的用户定义转换运算符,以将从转换
SX
为TX
。The most specific user-defined conversion operator is invoked to convert fromSX
toTX
. - 如果不
TX
为T
,则执行从到的标准显式转换TX
T
。IfTX
is notT
, then a standard explicit conversion fromTX
toT
is performed.
- 如果不
匿名函数转换Anonymous function conversions
Anonymous_method_expression 或 lambda_expression 归类为匿名函数 (匿名函数表达式) 。An anonymous_method_expression or lambda_expression is classified as an anonymous function (Anonymous function expressions). 表达式没有类型,但可以隐式转换为兼容的委托类型或表达式树类型。The expression does not have a type but can be implicitly converted to a compatible delegate type or expression tree type. 具体而言,匿名函数 F
与所提供的委托类型兼容 D
:Specifically, an anonymous function F
is compatible with a delegate type D
provided:
- 如果
F
包含一个 anonymous_function_signature,则D
和F
具有相同数量的参数。IfF
contains an anonymous_function_signature, thenD
andF
have the same number of parameters. - 如果不
F
包含 anonymous_function_signature,则D
只要没有的参数D
具有参数修饰符,就可以具有零个或多个任意类型的参数out
。IfF
does not contain an anonymous_function_signature, thenD
may have zero or more parameters of any type, as long as no parameter ofD
has theout
parameter modifier. - 如果
F
具有显式类型化参数列表,则中的每个参数D
都具有与中相应参数相同的类型和修饰符F
。IfF
has an explicitly typed parameter list, each parameter inD
has the same type and modifiers as the corresponding parameter inF
. - 如果
F
具有隐式类型的参数列表,则D
不包含ref
或out
参数。IfF
has an implicitly typed parameter list,D
has noref
orout
parameters. - 如果的主体
F
是一个表达式,并且D
具有void
返回类型或F
为 async 并且D
具有返回类型Task
,则当的每个参数都为F
指定中的相应参数的类型时,的D
主体F
为 (wrt 表达式) 的有效表达式,该表达式将允许作为) 的 statement_expression (表达式语句 。If the body ofF
is an expression, and eitherD
has avoid
return type orF
is async andD
has the return typeTask
, then when each parameter ofF
is given the type of the corresponding parameter inD
, the body ofF
is a valid expression (wrt Expressions) that would be permitted as a statement_expression (Expression statements). - 如果的主体
F
是一个语句块,并且D
具有void
返回类型或F
为 async 并且D
具有返回类型Task
,则当的每个参数都为F
指定中的相应参数的类型时,的D
正文F
为有效语句块 (wrt 块) ,其中没有return
语句指定表达式。If the body ofF
is a statement block, and eitherD
has avoid
return type orF
is async andD
has the return typeTask
, then when each parameter ofF
is given the type of the corresponding parameter inD
, the body ofF
is a valid statement block (wrt Blocks) in which noreturn
statement specifies an expression. - 如果的主体
F
是一个表达式,并且F
为非 async 并且D
具有非 void 返回类型T
,或者F
是异步的,并且D
具有返回类型,则Task<T>
当的每个参数F
都为指定中的相应参数的类型时,的D
主体F
将是有效的表达式, (可隐 式转换为) 的 wrt 表达式T
。If the body ofF
is an expression, and eitherF
is non-async andD
has a non-void return typeT
, orF
is async andD
has a return typeTask<T>
, then when each parameter ofF
is given the type of the corresponding parameter inD
, the body ofF
is a valid expression (wrt Expressions) that is implicitly convertible toT
. - 如果的主体
F
是语句块,和 均F
为非 async 并且D
具有非 void 返回类型T
, 或者F
是异步的,并且D
具有返回类型,则Task<T>
当的每个参数的类型为F
中的相应参数时D
,的主体F
为有效语句块 (wrt 块 , 其中每个语句都)return
指定一个可隐式转换为的表达式T
。If the body ofF
is a statement block, and eitherF
is non-async andD
has a non-void return typeT
, orF
is async andD
has a return typeTask<T>
, then when each parameter ofF
is given the type of the corresponding parameter inD
, the body ofF
is a valid statement block (wrt Blocks) with a non-reachable end point in which eachreturn
statement specifies an expression that is implicitly convertible toT
.
为了简洁起见,本部分对任务类型 Task
和 Task<T>
(异步函数) 使用缩写形式。For the purpose of brevity, this section uses the short form for the task types Task
and Task<T>
(Async functions).
F
Expression<D>
如果与 F
委托类型兼容,则 lambda 表达式与表达式树类型兼容 D
。A lambda expression F
is compatible with an expression tree type Expression<D>
if F
is compatible with the delegate type D
. 请注意,这不适用于匿名方法,只适用于 lambda 表达式。Note that this does not apply to anonymous methods, only lambda expressions.
某些 lambda 表达式不能转换为表达式树类型:即使转换 存在,它也会在编译时失败。Certain lambda expressions cannot be converted to expression tree types: Even though the conversion exists, it fails at compile-time. 如果 lambda 表达式为,则为这种情况:This is the case if the lambda expression:
- 具有 块 体Has a block body
- 包含简单赋值运算符或复合赋值运算符Contains simple or compound assignment operators
- 包含动态绑定的表达式Contains a dynamically bound expression
- 为异步Is async
下面的示例使用泛型委托类型, Func<A,R>
该类型表示一个函数,该函数采用类型的参数 A
并返回类型的值 R
:The examples that follow use a generic delegate type Func<A,R>
which represents a function that takes an argument of type A
and returns a value of type R
:
delegate R Func<A,R>(A arg);
在分配中In the assignments
Func<int,int> f1 = x => x + 1; // Ok
Func<int,double> f2 = x => x + 1; // Ok
Func<double,int> f3 = x => x + 1; // Error
Func<int, Task<int>> f4 = async x => x + 1; // Ok
每个匿名函数的参数和返回类型都是从匿名函数所分配到的变量类型确定的。the parameter and return types of each anonymous function are determined from the type of the variable to which the anonymous function is assigned.
第一次分配成功将匿名函数转换为委托类型 Func<int,int>
,因为当 x
给定类型时 int
, x+1
是可隐式转换为类型的有效表达式 int
。The first assignment successfully converts the anonymous function to the delegate type Func<int,int>
because, when x
is given type int
, x+1
is a valid expression that is implicitly convertible to type int
.
同样,第二个赋值成功将匿名函数转换为委托类型, Func<int,double>
因为) 类型的 (的结果可 x+1
int
隐式转换为 double
类型。Likewise, the second assignment successfully converts the anonymous function to the delegate type Func<int,double>
because the result of x+1
(of type int
) is implicitly convertible to type double
.
但是,第三个赋值是编译时错误,因为当 x
给定类型时, double
x+1
类型) (的结果 double
无法隐式转换为类型 int
。However, the third assignment is a compile-time error because, when x
is given type double
, the result of x+1
(of type double
) is not implicitly convertible to type int
.
第四个赋值成功将匿名 async 函数转换为委托类型, Func<int, Task<int>>
因为) 类型的 (的结果可 x+1
int
隐式转换为该 int
任务类型的结果类型 Task<int>
。The fourth assignment successfully converts the anonymous async function to the delegate type Func<int, Task<int>>
because the result of x+1
(of type int
) is implicitly convertible to the result type int
of the task type Task<int>
.
匿名函数可能会影响重载决策,并参与类型推理。Anonymous functions may influence overload resolution, and participate in type inference. 有关更多详细信息,请参阅 函数成员 。See Function members for further details.
匿名函数转换到委托类型的计算Evaluation of anonymous function conversions to delegate types
将匿名函数转换为委托类型会生成一个委托实例,该实例引用匿名函数,并且 (可能为空,这是在计算时处于活动状态的已捕获外部变量的) 集。Conversion of an anonymous function to a delegate type produces a delegate instance which references the anonymous function and the (possibly empty) set of captured outer variables that are active at the time of the evaluation. 调用委托时,将执行匿名函数的主体。When the delegate is invoked, the body of the anonymous function is executed. 使用委托引用的捕获外部变量集来执行正文中的代码。The code in the body is executed using the set of captured outer variables referenced by the delegate.
从匿名函数生成的委托的调用列表包含单个项。The invocation list of a delegate produced from an anonymous function contains a single entry. 委托的确切目标对象和目标方法未指定。The exact target object and target method of the delegate are unspecified. 具体而言,它是未指定的,即委托的目标对象是 null
、 this
封闭函数成员的值还是其他某个对象。In particular, it is unspecified whether the target object of the delegate is null
, the this
value of the enclosing function member, or some other object.
允许 (但不要求) 返回同一个委托实例,但不允许将语义相同的匿名函数(具有相同的) ()转换为同一委托类型。Conversions of semantically identical anonymous functions with the same (possibly empty) set of captured outer variable instances to the same delegate types are permitted (but not required) to return the same delegate instance. 此处使用的术语在语义上是相同的,这意味着在所有情况下,匿名函数的执行将在给定相同参数的情况下生成相同的效果。The term semantically identical is used here to mean that execution of the anonymous functions will, in all cases, produce the same effects given the same arguments. 此规则允许对如下代码进行优化。This rule permits code such as the following to be optimized.
delegate double Function(double x);
class Test
{
static double[] Apply(double[] a, Function f) {
double[] result = new double[a.Length];
for (int i = 0; i < a.Length; i++) result[i] = f(a[i]);
return result;
}
static void F(double[] a, double[] b) {
a = Apply(a, (double x) => Math.Sin(x));
b = Apply(b, (double y) => Math.Sin(y));
...
}
}
由于两个匿名函数委托具有相同的 (空) 一组捕获的外部变量,并且由于匿名函数在语义上是相同的,因此允许编译器使委托引用相同的目标方法。Since the two anonymous function delegates have the same (empty) set of captured outer variables, and since the anonymous functions are semantically identical, the compiler is permitted to have the delegates refer to the same target method. 的确,允许编译器从两个匿名函数表达式返回完全相同的委托实例。Indeed, the compiler is permitted to return the very same delegate instance from both anonymous function expressions.
对表达式树类型的匿名函数转换的计算Evaluation of anonymous function conversions to expression tree types
将匿名函数转换为表达式树类型会生成表达式树, (表达式树类型) 。Conversion of an anonymous function to an expression tree type produces an expression tree (Expression tree types). 更准确地说,对匿名函数转换的评估导致了表示匿名函数本身的结构的对象结构。More precisely, evaluation of the anonymous function conversion leads to the construction of an object structure that represents the structure of the anonymous function itself. 表达式树的准确结构以及用于创建它的确切过程是定义的实现。The precise structure of the expression tree, as well as the exact process for creating it, are implementation defined.
实现示例Implementation example
本部分介绍了使用其他 c # 构造实现的匿名函数转换的可能实现。This section describes a possible implementation of anonymous function conversions in terms of other C# constructs. 此处所述的实现基于 Microsoft c # 编译器所使用的相同原则,但它并不是强制性实现,也不是唯一可行的方法。The implementation described here is based on the same principles used by the Microsoft C# compiler, but it is by no means a mandated implementation, nor is it the only one possible. 它只是简单地提到了转换为表达式树,因为其确切语义超出了本规范的范围。It only briefly mentions conversions to expression trees, as their exact semantics are outside the scope of this specification.
本部分的其余部分提供了一些代码示例,其中包含具有不同特征的匿名函数。The remainder of this section gives several examples of code that contains anonymous functions with different characteristics. 对于每个示例,提供了对仅使用其他 c # 构造的代码的相应转换。For each example, a corresponding translation to code that uses only other C# constructs is provided. 在这些示例中, D
假定使用标识符表示以下委托类型:In the examples, the identifier D
is assumed by represent the following delegate type:
public delegate void D();
匿名函数的最简单形式是捕获无外部变量:The simplest form of an anonymous function is one that captures no outer variables:
class Test
{
static void F() {
D d = () => { Console.WriteLine("test"); };
}
}
这可以转换为引用编译器生成的静态方法(在其中放置匿名函数的代码)的委托实例化:This can be translated to a delegate instantiation that references a compiler generated static method in which the code of the anonymous function is placed:
class Test
{
static void F() {
D d = new D(__Method1);
}
static void __Method1() {
Console.WriteLine("test");
}
}
在下面的示例中,匿名函数引用的实例成员 this
:In the following example, the anonymous function references instance members of this
:
class Test
{
int x;
void F() {
D d = () => { Console.WriteLine(x); };
}
}
这可以转换为包含匿名函数代码的编译器生成的实例方法:This can be translated to a compiler generated instance method containing the code of the anonymous function:
class Test
{
int x;
void F() {
D d = new D(__Method1);
}
void __Method1() {
Console.WriteLine(x);
}
}
在此示例中,匿名函数捕获本地变量:In this example, the anonymous function captures a local variable:
class Test
{
void F() {
int y = 123;
D d = () => { Console.WriteLine(y); };
}
}
局部变量的生存期现在必须至少扩展到匿名函数委托的生存期。The lifetime of the local variable must now be extended to at least the lifetime of the anonymous function delegate. 这可以通过将本地变量 "提升" 到编译器生成的类的字段来实现。This can be achieved by "hoisting" the local variable into a field of a compiler generated class. 实例化局部变量 (实例 化 局部变量) 然后与创建编译器生成的类的实例,并且访问本地变量对应于访问编译器生成的类的实例中的字段。Instantiation of the local variable (Instantiation of local variables) then corresponds to creating an instance of the compiler generated class, and accessing the local variable corresponds to accessing a field in the instance of the compiler generated class. 此外,匿名函数会成为编译器生成的类的实例方法:Furthermore, the anonymous function becomes an instance method of the compiler generated class:
class Test
{
void F() {
__Locals1 __locals1 = new __Locals1();
__locals1.y = 123;
D d = new D(__locals1.__Method1);
}
class __Locals1
{
public int y;
public void __Method1() {
Console.WriteLine(y);
}
}
}
最后,下面的匿名函数捕获和 this
两个具有不同生存期的局部变量:Finally, the following anonymous function captures this
as well as two local variables with different lifetimes:
class Test
{
int x;
void F() {
int y = 123;
for (int i = 0; i < 10; i++) {
int z = i * 2;
D d = () => { Console.WriteLine(x + y + z); };
}
}
}
在这里,将为每个在其中捕获局部变量的语句块创建一个编译器生成的类,以便不同块中的局部变量可以具有独立生存期。Here, a compiler generated class is created for each statement block in which locals are captured such that the locals in the different blocks can have independent lifetimes. 的实例 __Locals2
(内部语句块的编译器生成的类)包含局部变量 z
和引用实例的字段 __Locals1
。An instance of __Locals2
, the compiler generated class for the inner statement block, contains the local variable z
and a field that references an instance of __Locals1
. 的一个实例 __Locals1
,它是外部语句块的编译器生成的类,其中包含局部变量 y
和引用 this
封闭函数成员的字段。An instance of __Locals1
, the compiler generated class for the outer statement block, contains the local variable y
and a field that references this
of the enclosing function member. 利用这些数据结构,可以通过的实例访问所有捕获的外部变量 __Local2
,匿名函数的代码就可以作为该类的实例方法实现。With these data structures it is possible to reach all captured outer variables through an instance of __Local2
, and the code of the anonymous function can thus be implemented as an instance method of that class.
class Test
{
void F() {
__Locals1 __locals1 = new __Locals1();
__locals1.__this = this;
__locals1.y = 123;
for (int i = 0; i < 10; i++) {
__Locals2 __locals2 = new __Locals2();
__locals2.__locals1 = __locals1;
__locals2.z = i * 2;
D d = new D(__locals2.__Method1);
}
}
class __Locals1
{
public Test __this;
public int y;
}
class __Locals2
{
public __Locals1 __locals1;
public int z;
public void __Method1() {
Console.WriteLine(__locals1.__this.x + __locals1.y + z);
}
}
}
在此处用于捕获局部变量的相同技术也可以在将匿名函数转换为表达式树时使用:对编译器生成的对象的引用可以存储在表达式树中,对局部变量的访问可表示为这些对象上的字段访问。The same technique applied here to capture local variables can also be used when converting anonymous functions to expression trees: References to the compiler generated objects can be stored in the expression tree, and access to the local variables can be represented as field accesses on these objects. 此方法的优点是允许在委托和表达式树之间共享 "提升" 的局部变量。The advantage of this approach is that it allows the "lifted" local variables to be shared between delegates and expression trees.
方法组转换Method group conversions
隐式转换 () 存在从方法组 (表达式分类) 到兼容的委托类型的隐式转换。An implicit conversion (Implicit conversions) exists from a method group (Expression classifications) to a compatible delegate type. 给定委托类型 D
和 E
归类为方法组的表达式时,存在从到的隐式转换 E
D
E
。如果包含至少一个适用于其正常窗体的方法 (适用的 函数成员) 到通过使用的参数类型和修饰符构造的参数列表 D
,如下所述。Given a delegate type D
and an expression E
that is classified as a method group, an implicit conversion exists from E
to D
if E
contains at least one method that is applicable in its normal form (Applicable function member) to an argument list constructed by use of the parameter types and modifiers of D
, as described in the following.
以下中描述了从方法组转换为委托类型的编译时应用程序 E
D
。The compile-time application of a conversion from a method group E
to a delegate type D
is described in the following. 请注意,是否存在从到的隐式转换, E
D
并不保证转换的编译时应用程序不会出错。Note that the existence of an implicit conversion from E
to D
does not guarantee that the compile-time application of the conversion will succeed without error.
M
选择与方法调用对应的单个方法 (方法调用) 的方法调用E(A)
,并进行以下修改:A single methodM
is selected corresponding to a method invocation (Method invocations) of the formE(A)
, with the following modifications:- 参数列表
A
是表达式的列表,每个表达式都归类为变量,并且具有类型和修饰符 (ref
或的out
formal_parameter_list 中的相应参数)D
。The argument listA
is a list of expressions, each classified as a variable and with the type and modifier (ref
orout
) of the corresponding parameter in the formal_parameter_list ofD
. - 考虑的候选方法只是那些适用于其正常形式 (适用的函数成员) ,而不是仅在其展开形式中适用的方法。The candidate methods considered are only those methods that are applicable in their normal form (Applicable function member), not those applicable only in their expanded form.
- 参数列表
- 如果 方法调用 的算法产生错误,则会发生编译时错误。If the algorithm of Method invocations produces an error, then a compile-time error occurs. 否则,该算法将生成单个最佳方法,
M
该方法的参数数目与相同D
,转换被视为存在。Otherwise the algorithm produces a single best methodM
having the same number of parameters asD
and the conversion is considered to exist. - 所选方法
M
必须兼容 (委托类型) 委托兼容性D
,否则将发生编译时错误。The selected methodM
must be compatible (Delegate compatibility) with the delegate typeD
, or otherwise, a compile-time error occurs. - 如果所选方法
M
是实例方法,则与关联的实例表达式E
确定委托的目标对象。If the selected methodM
is an instance method, the instance expression associated withE
determines the target object of the delegate. - 如果所选方法 M 是通过实例表达式上的成员访问方式表示的扩展方法,则该实例表达式将确定委托的目标对象。If the selected method M is an extension method which is denoted by means of a member access on an instance expression, that instance expression determines the target object of the delegate.
- 转换结果为类型的值
D
,即引用所选方法和目标对象的新创建的委托。The result of the conversion is a value of typeD
, namely a newly created delegate that refers to the selected method and target object. - 请注意,如果 方法调用 的算法找不到实例方法,但在将调用
E(A)
作为扩展方法调用处理 (扩展 方法调用) ,则此过程可能会导致创建扩展方法的委托。Note that this process can lead to the creation of a delegate to an extension method, if the algorithm of Method invocations fails to find an instance method but succeeds in processing the invocation ofE(A)
as an extension method invocation (Extension method invocations). 因此,创建的委托将捕获扩展方法以及其第一个参数。A delegate thus created captures the extension method as well as its first argument.
下面的示例演示方法组转换:The following example demonstrates method group conversions:
delegate string D1(object o);
delegate object D2(string s);
delegate object D3();
delegate string D4(object o, params object[] a);
delegate string D5(int i);
class Test
{
static string F(object o) {...}
static void G() {
D1 d1 = F; // Ok
D2 d2 = F; // Ok
D3 d3 = F; // Error -- not applicable
D4 d4 = F; // Error -- not applicable in normal form
D5 d5 = F; // Error -- applicable but not compatible
}
}
赋值 d1
隐式将方法组转换 F
为类型的值 D1
。The assignment to d1
implicitly converts the method group F
to a value of type D1
.
的赋值 d2
演示了如何创建一个委托,该委托指向 (逆变) 参数类型和派生程度更高的 (协变) 返回类型的派生方法。The assignment to d2
shows how it is possible to create a delegate to a method that has less derived (contravariant) parameter types and a more derived (covariant) return type.
d3
如果该方法不适用,则分配为显示不存在转换的情况。The assignment to d3
shows how no conversion exists if the method is not applicable.
用于 d4
显示此方法必须以其正常形式适用的方式的赋值。The assignment to d4
shows how the method must be applicable in its normal form.
用于 d5
显示如何允许委托和方法的参数和返回类型不同于引用类型的赋值。The assignment to d5
shows how parameter and return types of the delegate and method are allowed to differ only for reference types.
与所有其他隐式和显式转换一样,转换运算符可用于显式执行方法组转换。As with all other implicit and explicit conversions, the cast operator can be used to explicitly perform a method group conversion. 因此,示例Thus, the example
object obj = new EventHandler(myDialog.OkClick);
可以改为写入could instead be written
object obj = (EventHandler)myDialog.OkClick;
方法组可能会影响重载决策,并参与类型推理。Method groups may influence overload resolution, and participate in type inference. 有关更多详细信息,请参阅 函数成员 。See Function members for further details.
方法组转换的运行时计算如下所示:The run-time evaluation of a method group conversion proceeds as follows:
- 如果在编译时选择的方法是实例方法,或者它是作为实例方法访问的扩展方法,则将从与关联的实例表达式确定委托的目标对象
E
:If the method selected at compile-time is an instance method, or it is an extension method which is accessed as an instance method, the target object of the delegate is determined from the instance expression associated withE
:- 计算实例表达式。The instance expression is evaluated. 如果此计算导致异常,则不执行其他步骤。If this evaluation causes an exception, no further steps are executed.
- 如果实例表达式为 reference_type,则由实例表达式计算的值将成为目标对象。If the instance expression is of a reference_type, the value computed by the instance expression becomes the target object. 如果所选的方法是实例方法,并且目标对象为
null
,System.NullReferenceException
则会引发,而不执行进一步的步骤。If the selected method is an instance method and the target object isnull
, aSystem.NullReferenceException
is thrown and no further steps are executed. - 如果实例表达式为 value_type,则会执行装箱运算 (装箱转换 ,) 将值转换为对象,此对象将成为目标对象。If the instance expression is of a value_type, a boxing operation (Boxing conversions) is performed to convert the value to an object, and this object becomes the target object.
- 否则,所选方法为静态方法调用的一部分,并且委托的目标对象是
null
。Otherwise the selected method is part of a static method call, and the target object of the delegate isnull
. - 分配委托类型的新实例
D
。A new instance of the delegate typeD
is allocated. 如果没有足够的内存可用于分配新的实例,System.OutOfMemoryException
则会引发,而不执行进一步的步骤。If there is not enough memory available to allocate the new instance, aSystem.OutOfMemoryException
is thrown and no further steps are executed. - 使用对在编译时确定的方法以及对上面计算的目标对象的引用来初始化新的委托实例。The new delegate instance is initialized with a reference to the method that was determined at compile-time and a reference to the target object computed above.