目标类型的条件表达式

注意

本文是特性规范。 此规范是功能的设计文档。 它包括建议的规范变更,以及功能设计和开发过程中所需的信息。 这些文章将持续发布,直至建议的规范变更最终确定并纳入当前的 ECMA 规范。

功能规范与已完成的实现之间可能存在一些差异。 这些差异记录在相关的语言设计会议 (LDM) 说明中。

可以在有关规范的文章中了解更多有关将功能规范子块纳入 C# 语言标准的过程。

支持者问题:https://github.com/dotnet/csharplang/issues/2460

条件表达式转换

对于条件表达式 c ? e1 : e2,当

  1. 没有适合 e1e2 的常见类型,或者
  2. 存在一个常见类型,但表达式 e1e2 中的一个没有隐式转换为该类型

我们定义了一个新的隐式条件表达式转换,它允许从条件表达式隐式转换为任何类型 T,其中存在从 e1T 以及从 e2T 的表达式转换。 如果一个条件表达式既没有 e1e2 之间的公共类型,也没有经过条件表达式转换,则这是一个错误。

更好的从表达式转换

我们更改

更好的从表达式转换

给定从表达式 C1 转换为类型 E的隐式转换 T1,以及从表达式 C2 转换为类型 E的隐式转换 T2,当 C1 不与 完全匹配时, 是一个比 C2 更好的 T2,并且至少满足以下条件之一:

接收方

更好的从表达式转换

给定从表达式 C1 转换为类型 E的隐式转换 T1,以及从表达式 C2 转换为类型 E的隐式转换 T2,当 C1 不与 完全匹配时, 是一个比 C2 更好的 T2,并且至少满足以下条件之一:

  • E 完全匹配 T1 (§12.6.4.5)
  • C1 不是条件表达式转换C2条件表达式转换
  • T1 是比 T2 (§12.6.4.7) 更好的转换目标,C1C2都是条件表达式转换,或者都不是条件表达式转化

Cast 表达式

当前的 C# 语言规范指出

形式为 (T)E 会将 T 的值显式转换 (§10.3) 为类型 E,其中 是一个类型E 是一个 T

在存在条件表达式转换的情况下,可能有不止一个从 ET 的转换。 通过添加条件表达式转换,我们更喜欢任何其他转换为条件表达式转化,并且仅将条件表达式转换作为最后手段。

设计说明

更改为更好的从表达式转换的原因是为了处理如下情况:

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 更适合(因为 shortlong 转换目标)。 此重大更改似乎不那么严重,因为它不会以无提示方式更改现有程序的行为。

在强制转换表达式上添加注释的原因是为了处理这样的情况:

_ = (short)(b ? 1 : 2);

此程序当前使用从 intshort的显式转换,我们希望保留此程序的当前语言含义。 更改在运行时是无法观察到的,但使用以下程序,可以观察到更改:

_ = (A)(b ? c : d);

其中,c 的类型为 Cd 的类型为 D,并且存在从 CD 的隐式用户定义转换,以及从 DA 的隐式用户定义转换,以及从 CA 的隐式用户定义转换。 如果这段代码是在 C# 9.0 之前编译的,则当 b 为 true 时,我们将从 c 转换为 D,然后转换为 A。 如果使用条件表达式转换,则当 b 为 true 时,我们将直接从 c 转换为 A,这将执行不同的用户代码序列。 因此,我们将条件表达式转换视为强制转换中的最后手段,以保留现有行为。