目标类型的条件表达式
注意
本文是特性规范。 此规范是功能的设计文档。 它包括建议的规范变更,以及功能设计和开发过程中所需的信息。 这些文章将持续发布,直至建议的规范变更最终确定并纳入当前的 ECMA 规范。
功能规范与已完成的实现之间可能存在一些差异。 这些差异记录在相关的语言设计会议 (LDM) 说明中。
可以在有关规范的文章中了解更多有关将功能规范子块纳入 C# 语言标准的过程。
支持者问题:https://github.com/dotnet/csharplang/issues/2460
条件表达式转换
对于条件表达式 c ? e1 : e2
,当
- 没有适合
e1
和e2
的常见类型,或者 - 存在一个常见类型,但表达式
e1
或e2
中的一个没有隐式转换为该类型
我们定义了一个新的隐式条件表达式转换,它允许从条件表达式隐式转换为任何类型 T
,其中存在从 e1
到 T
以及从 e2
到 T
的表达式转换。 如果一个条件表达式既没有 e1
和 e2
之间的公共类型,也没有经过条件表达式转换,则这是一个错误。
更好的从表达式转换
我们更改
更好的从表达式转换
给定从表达式
C1
转换为类型E
的隐式转换T1
,以及从表达式C2
转换为类型E
的隐式转换T2
,当C1
不与 完全匹配时, 是一个比C2
更好的T2
,并且至少满足以下条件之一:
接收方
更好的从表达式转换
给定从表达式
C1
转换为类型E
的隐式转换T1
,以及从表达式C2
转换为类型E
的隐式转换T2
,当C1
不与 完全匹配时, 是一个比C2
更好的T2
,并且至少满足以下条件之一:
Cast 表达式
当前的 C# 语言规范指出
形式为 的
(T)E
会将T
的值显式转换 (§10.3) 为类型E
,其中 是一个类型,E
是一个T
。
在存在条件表达式转换的情况下,可能有不止一个从 E
到 T
的转换。 通过添加条件表达式转换,我们更喜欢任何其他转换为条件表达式转化,并且仅将条件表达式转换作为最后手段。
设计说明
更改为更好的从表达式转换的原因是为了处理如下情况:
M(b ? 1 : 2);
void M(short);
void M(long);
此方法确实有两个小缺点。 首先,它与 switch 表达式不完全相同:
M(b ? 1 : 2); // calls M(long)
M(b switch { true => 1, false => 2 }); // calls M(short)
这仍然是一项重大更改,但其范围不太可能影响实际程序:
M(b ? 1 : 2, 1); // calls M(long, long) without this feature; ambiguous with this feature.
M(short, short);
M(long, long);
这变得模棱两可,因为转换到 long
对第一个参数更适合(因为它没有使用 条件表达式转换),但对第二个参数的转换到 short
更适合(因为 short
是 long
转换目标)。 此重大更改似乎不那么严重,因为它不会以无提示方式更改现有程序的行为。
在强制转换表达式上添加注释的原因是为了处理这样的情况:
_ = (short)(b ? 1 : 2);
此程序当前使用从 int
到 short
的显式转换,我们希望保留此程序的当前语言含义。 更改在运行时是无法观察到的,但使用以下程序,可以观察到更改:
_ = (A)(b ? c : d);
其中,c
的类型为 C
,d
的类型为 D
,并且存在从 C
到 D
的隐式用户定义转换,以及从 D
到 A
的隐式用户定义转换,以及从 C
到 A
的隐式用户定义转换。 如果这段代码是在 C# 9.0 之前编译的,则当 b
为 true 时,我们将从 c
转换为 D
,然后转换为 A
。 如果使用条件表达式转换,则当 b
为 true 时,我们将直接从 c
转换为 A
,这将执行不同的用户代码序列。 因此,我们将条件表达式转换视为强制转换中的最后手段,以保留现有行为。