bla*_*234 94 c# java ternary-operator conditional-operator
我是C#新手,我遇到了一个问题.处理三元运算符(? :)时,C#和Java之间存在差异.
在以下代码段中,为什么第4行不起作用?编译器显示错误消息there is no implicit conversion between 'int' and 'string'.第5行不起作用.两者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
Run Code Online (Sandbox Code Playgroud)
但是,相同的代码适用于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
Run Code Online (Sandbox Code Playgroud)
缺少C#中的哪种语言功能?如果有,为什么不添加?
Jer*_*vel 106
通过C#5语言规范部分7.14:条件运算符,我们可以看到以下内容:
如果x的类型为X,则y的类型为Y.
如果从X到Y存在隐式转换(第6.1节),而不是从Y到X,则Y是条件表达式的类型.
如果从Y到X存在隐式转换(第6.1节),而不是从X到Y,则X是条件表达式的类型.
否则,无法确定表达式类型,并发生编译时错误
换句话说:它试图找到x和y是否能够被转换为海誓山盟并且如果不是,则产生编译错误.在我们的例子中int,string没有显式或隐式转换,所以它不会编译.
将其与Java 7语言规范部分15.25对比:条件运算符:
- 如果第二个和第三个操作数具有相同的类型(可以是null类型),那么这就是条件表达式的类型.(不)
- 如果第二个和第三个操作数之一是原始类型T,而另一个操作数的类型是对T应用装箱转换(第5.1.7节)的结果,那么条件表达式的类型是T.(NO)
- 如果第二个和第三个操作数之一是null类型而另一个操作数的类型是引用类型,则条件表达式的类型是该引用类型.(不)
- 否则,如果第二个和第三个操作数具有可转换(第5.1.8节)到数字类型的类型,则有几种情况:( 否)
- 否则,第二和第三操作数分别是S1和S2类型.设T1是将拳击转换应用于S1所产生的类型,让T2为应用到S2的装箱转换所产生的类型.
条件表达式的类型是将捕获转换(第5.1.10节)应用于lub(T1,T2)(第15.12.2.7节)的结果.(是)
并且,请看第15.12.2.7节.推断类型参数根据实际参数,我们可以看到它试图找到一个共同的祖先,它将作为用于调用它的调用的类型Object.Object 这是一个可接受的参数,因此呼叫将起作用.
Eri*_*ert 86
给出的答案是好的; 我想补充一点,这个C#规则是更通用的设计指南的结果.当被要求从几个选项之一推断出表达式的类型时,C#会选择其中最独特的一个.也就是说,如果你给C#一些选择,比如"长颈鹿,哺乳动物,动物"那么它可能会选择最一般的 - 动物 - 或者它可能会选择最具体的 - 长颈鹿 - 视情况而定.但它必须选择实际给出的选择之一.C#从不说"我的选择是在猫与狗之间,因此我会推断出Animal是最好的选择".这不是一个选择,所以C#不能选择它.
在三元运算符的情况下,C#尝试选择更通用的int和string类型,但两者都不是更通用的类型.C#决定不推断任何类型,而不是选择一个首先不是选择的类型.
我还注意到这符合C#的另一个设计原则:如果出现问题,请告诉开发人员.这种语言并没有说"我会猜到你的意思,如果可以的话,就会糊里糊涂".语言说"我觉得你在这里写了一些令人困惑的东西,我会告诉你这件事."
另外,我注意到C#并不是从变量到指定值的原因,而是另一个方向.C#没有说"你正在分配一个对象变量,因此表达式必须可以转换为对象,因此我将确保它是".相反,C#说:"这种表达必须有一个类型,我必须能够推断出该类型与对象兼容".由于表达式没有类型,因此会产生错误.
Mat*_*don 24
关于泛型部分:
Run Code Online (Sandbox Code Playgroud)two > six ? new List<int>() : new List<string>()
在C#中,编译器尝试将右侧表达式部分转换为某种常见类型; 由于List<int>和List<string>是两个不同的构造类型,一个不能被转换到另一个.
在Java中,编译器尝试查找公共超类型而不是转换,因此代码的编译涉及隐式使用通配符和类型擦除 ;
Run Code Online (Sandbox Code Playgroud)two > six ? new ArrayList<Integer>() : new ArrayList<String>()
具有编译类型ArrayList<?>(实际上,它也可以是,ArrayList<? extends Serializable>或者ArrayList<? extends Comparable<?>>,取决于使用上下文,因为它们都是常见的泛型超类型)和raw的运行时类型ArrayList(因为它是常见的原始超类型).
例如(自己测试),
void test( List<?> list ) {
System.out.println("foo");
}
void test( ArrayList<Integer> list ) { // note: can't use List<Integer> here
// since both test() methods would clash after the erasure
System.out.println("bar");
}
void test() {
test( true ? new ArrayList<Object>() : new ArrayList<Object>() ); // foo
test( true ? new ArrayList<Integer>() : new ArrayList<Object>() ); // foo
test( true ? new ArrayList<Integer>() : new ArrayList<Integer>() ); // bar
} // compiler automagically binds the correct generic QED
Run Code Online (Sandbox Code Playgroud)
在Java和C#(以及大多数其他语言)中,表达式的结果都有一个类型.对于三元运算符,有两个可能的子表达式针对结果进行求值,并且两者必须具有相同的类型.在Java的情况下,int可以Integer通过自动装箱将变量转换为a .现在既然Integer又String继承Object,它们可以通过简单的缩小转换转换为相同的类型.
另一方面,在C#中,a int是原语,并且没有隐式转换string或任何其他转换object.
这非常简单.string和int之间没有隐式转换.三元运算符需要最后两个操作数具有相同的类型.
尝试:
Write(two > six ? two.ToString() : "6");
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4595 次 |
| 最近记录: |