C# 和 Java 的三元运算符之间的区别(? :)

我是一个C#新手,我只是遇到了一个问题。在处理三元运算符 () 时,C# 和 Java 之间存在差异。? :

在下面的代码段中,为什么第 4 行不起作用?编译器显示错误消息 。第 5 行也不起作用。两者都是对象,不是吗?there is no implicit conversion between 'int' and 'string'List

int two = 2;
double six = 6.0;
Write(two > six ? two : six); //param: double
Write(two > six ? two : "6"); //param: not object
Write(two > six ? new List<int>() : new List<string>()); //param: not object

但是,相同的代码在Java中工作:

int two = 2;
double six = 6.0;
System.out.println(two > six ? two : six); //param: double
System.out.println(two > six ? two : "6"); //param: Object
System.out.println(two > six ? new ArrayList<Integer>()
                   : new ArrayList<String>()); //param: Object

C# 中缺少哪些语言功能?如果有的话,为什么不添加?


答案 1

浏览 C# 5 语言规范部分 7.14:条件运算符,我们可以看到以下内容:

  • 如果 x 具有类型 X,而 y 具有类型 Y,则

    • 如果隐式转换 (§6.1) 存在从 X 到 Y,但不存在从 Y 到 X 的隐式转换 (§6.1),则 Y 是条件表达式的类型。

    • 如果隐式转换 (§6.1) 存在从 Y 到 X,但不存在从 X 到 Y 的隐式转换 (§6.1),则 X 是条件表达式的类型。

    • 否则,无法确定表达式类型,并发生编译时错误

换句话说:它试图找出x和y是否可以相互转换,否则会发生编译错误。在我们的例子中,没有显式或隐式转换,因此它不会编译。intstring

将此与 Java 7 语言规范第 15.25 节:条件运算符进行对比:

  • 如果第二个和第三个操作数具有相同的类型(可能是 null 类型),则这就是条件表达式的类型。()
  • 如果第二个和第三个操作数之一是基元类型 T,而另一个操作数的类型是将装箱转换 (§5.1.7) 应用于 T 的结果,则条件表达式的类型为 T。(NO))
  • 如果第二个和第三个操作数之一为 null 类型,而另一个操作数的类型为引用类型,则条件表达式的类型为该引用类型。()
  • 否则,如果第二个和第三个操作数具有可转换为数值类型的类型 (§5.1.8),则有以下几种情况:(NO)
  • 否则,第二个和第三个操作数分别为 S1 和 S2 类型。设 T1 是将装箱转换应用于 S1 所得到的类型,让 T2 是将装箱转换应用于 S2 所得到的类型。
    条件表达式的类型是将捕获转换 (§5.1.10) 应用于 lub(T1, T2) (§15.12.2.7) 的结果。()

而且,看看第15.12.2.7节。根据实际参数推断类型参数,我们可以看到它试图找到一个共同的祖先,该祖先将用作用于调用的类型,该类型将其与. 一个可接受的参数,因此调用将起作用。ObjectObject


答案 2

给出的答案是好的;我想补充一点,C#的这个规则是更通用的设计指南的结果。当系统要求您从多个选项之一中推断表达式的类型时,C# 会选择其中唯一的最佳选项。也就是说,如果你给C#一些选择,比如“长颈鹿,哺乳动物,动物”,那么它可能会选择最一般的动物,或者它可能会选择最具体的长颈鹿,这取决于具体情况。但它必须选择它实际给予的选择之一。C#从来不会说“我的选择是在猫和狗之间,因此我会推断动物是最好的选择”。这不是一个给定的选择,所以C#不能选择它。

对于三元运算符,C# 尝试选择更通用的 int 和字符串类型,但也不是更通用的类型。C# 不是选择一个一开始就不是选择的类型(如对象),而是决定无法推断出任何类型。

我还注意到,这与C#的另一个设计原则是一致的:如果看起来有问题,告诉开发人员。语言没有说“我会猜你的意思,如果可以的话,我会混在一起”。语言说:“我认为你在这里写了一些令人困惑的东西,我要告诉你。

另外,我注意到C#不会从变量推理到分配的值,而是从另一个方向推理。C#没有说“你正在分配给一个对象变量,因此表达式必须是可转换为对象的,因此我将确保它是”。相反,C#说“这个表达式必须有一个类型,我必须能够推断出该类型与对象兼容”。由于表达式没有类型,因此会产生错误。


推荐