查看 Target-Typed Conditional Expression in C# 9 的文档.
在引入此功能后,文档中针对以下场景引用了歧义,但它仍然似乎每次都会调用M(long, long)
时间。即没有歧义?
M(b ? 1 : 2, 1); // calls M(long, long) without this feature; ambiguous with this feature. static void M(short i, short ii) => Console.WriteLine("short"); static void M(long i, long ii) => Console.WriteLine("long");
编译为:
public static void Main()
{
M(1L, 1L);
}
private static void M(short i, short ii) { Console.WriteLine("short, short"); }
private static void M(long i, long ii) { Console.WriteLine("long, long");
最佳答案
您所描述的情况的歧义完全是内部的。它不会暴露给用户。
为了清楚起见,情况是这样的:
static void Main()
{
M(1, 2); // Case A
M(true ? 1 : 2, 3); // Case B
bool b = true;
M(b ? 1 : 2, 3); // Case C
}
static void M(short a, short b) => Console.WriteLine($"{a} {b} {a.GetType()}");
static void M(long a, long b) => Console.WriteLine($"{a} {b} {a.GetType()}");
情况 A 和 B 可以由构建器进行评估(情况 B 生成 IL 代码 M(1, 3);
- 条件甚至不会呈现给运行时),因此两者都解析为short
实现,但情况 C 是歧义所在。
当运行时需要决定调用哪个版本时,它会执行第一遍并确定两个表达式解析为不同的类型。 b? 1 : 2
单独考虑时解析为 int
,3
也解析为 int
,但在上下文中对于此问题,模式匹配器需要将两者解析为 short
或 long
。
模式匹配器不想完全评估 b 吗? 1 : 2
(或者甚至确定可能的类型 - 请记住这可能是一个昂贵的嵌套情况),但它已被预先确定为 int
类型。 3
可以表示为 short
以匹配第一种情况,但 int
不能隐式转换为 short
,只到long
,所以它迈出了第一步。
因此,我们调用了 M(long, Short)
类型的 M
,这是不明确的。这可以通过以下任一方法解决:
- 将第二个参数
3
隐式转换为long
- 计算第一个参数
b ? 1 : 2
看看是否可以表示为short
当出现这些选项时,如果该选项存在,运行时将始终执行第一个选项。来自 proposal您发布的内容已通过以下方式“澄清”:
The updated terminology引用(新提案是 here ),在这种情况下,C1
是上面列表中的选项 1(不是条件表达式转换 - 即隐式),而 C2
是选项 2(是条件表达式转换),因此 C1
被认为“更好”。
链接中的最后一行为我澄清了事情:
Therefore we treat the conditional expression conversion as a last resort in a cast, to preserve existing behavior.
基本上,它会猜测最适合的是什么,而在 b 中? 1 : 2
,两个结果都解析为 int
,因此在决定调用哪个方法时,它要做的最后事情就是将该条件评估为发现 short
效果更好,并且 int
和 short
都可以隐式转换为 long
当然,这可以用 M((short)(b ? 1 : 2), 3);
强制执行,但这有什么乐趣呢?
希望这有帮助。
关于C# 目标类型条件表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76302041/