jsm*_*ith 3 c# casting ternary-operator boolean-expression
可能重复:
条件运算符无法隐式转换?
我遇到了一种奇怪的情况,想知道我为什么要这样做.我正在使用.NET 3.5.
这有效:
short foo;
if (isValid)
foo = -1;
else
foo = getFoo();
Run Code Online (Sandbox Code Playgroud)
这不起作用:
short foo;
foo = isValid ? -1 : getFoo();
Run Code Online (Sandbox Code Playgroud)
我必须打字-1:
short foo;
foo = isValid ? (short)-1 : getFoo();
Run Code Online (Sandbox Code Playgroud)
三元表达式有何不同?它认为-1是一个需要被转换为short的int.但为什么?
Eri*_*ert 11
一些东西.
首先,条件运算符是三元运算符,而不是第三运算符.
其次,我注意到在您的代码示例中,两个代码示例是等效的:
short foo;
if (isValid)
foo = -1;
else
getFoo();
Run Code Online (Sandbox Code Playgroud)
是不一样的
short foo = isValid ? (short)-1 : getFoo();
Run Code Online (Sandbox Code Playgroud)
如果isValid为false,前者将foo取消分配.无论isValid的值如何,后者都会赋予foo.
我认为你的意思
short foo;
if (isValid)
foo = -1;
else
foo = getFoo();
Run Code Online (Sandbox Code Playgroud)
而且,getFoo()返回short.
问题是为什么没有类型转换的条件运算符中的转换是非法的,但if语句的结果是合法的.
它在if语句中是合法的,因为规范的第6.1.9节规定:
如果constant-expression的值在目标类型的范围内,则int类型的常量表达式可以转换为sbyte,byte,short,ushort,uint或ulong类型.
-1是int类型的常量表达式,它在short范围内,因此可以隐式转换为short.
那么为什么条件表达式形成虚假?
我们必须清楚地确定的第一件事是条件表达式的类型是根据其内容而不是从其上下文确定的规则.赋值右侧的表达式类型不依赖于赋值给它的内容!假设你有
short M(short x){...}
int M(int x){...}
short y = M(-1);
Run Code Online (Sandbox Code Playgroud)
我不认为你会期望重载决议说"好吧,我通常会选择M(int),因为-1是一个int,但是不,我会选择M(短)而不是因为其他分配赢了"工作." 重载决议不知道结果的去向.它的工作是根据给定的参数计算出正确的重载,而不是基于调用的上下文.
确定条件表达式的类型的方式相同.我们不看它的类型,我们看一下表达式中的类型.
好的,所以我们已经确定将这个分配给short的事实与确定表达式的类型无关.但是这仍然留下了一个问题"为什么条件表达式的类型是int而不是short?"
这是一个非常好的问题.我们去看看规格.
?:运算符的第二个和第三个操作数x和y控制条件表达式的类型.
如果类型为X且y具有类型Y,则:
如果从X到Y存在隐式转换,但不存在从Y到X的隐式转换,则Y是条件表达式的类型.
如果从Y到X存在隐式转换,但不存在从X到Y的隐式转换,则X是条件表达式的类型.
否则,无法确定表达式类型,并发生编译时错误.
在这种情况下,操作数都有一个类型.(那里有关于"if x有一个类型......"的措辞是针对那里你有null或lambda的情况;那些没有类型!)第一个操作数是int类型,第二个是类型短.
隐式转换从short到int存在,但不是从int到short.因此,条件表达式的类型为int,不能将其赋值为short.
现在,可以说这个算法不尽如人意.我们可以使算法复杂化以处理存在两种可能的"候选"类型的所有情况 - 在这种情况下,int和short都是合理的候选者,因为当被视为特定表达式时,两个分支都可以转换为int和short两者,而不仅仅是有类型.在这种情况下,我们可以说两种类型中较小的一种是首选类型.
(有时在C#中我们说两种类型中更一般的类型是更好的类型,但在这种情况下你会希望我们选择更具体的类型.不幸的是,在这个特定的设计方面语言并不一致;我个人宁愿我们总是选择更具体的,但有类型推断场景,现在这将是一个突破性的变化.)
我在2006年考虑过这样做.在设计LINQ如何处理有多种类型可供选择的情况以及必须选择"最佳"的行为时,我们注意到条件运算符已经必须解决这个问题,并且此外,在C#2中,它实际上并没有根据规范实现.关于这一点存在很长时间的争论,我们最终对条件运算符的规范做了一些小的改动,使其更符合其实现的(和期望的)行为.然而,当有几个可供选择的时候,我们决定不再采用调整算法的较大改变来使用两种可能类型中较小的一种.
关于这个问题的一些思考,请参阅2006年的帖子:
因为-1默认是一个整数.编译器告诉您必须明确告诉它要做什么,而不是让编译器对您想要做的事情做出假设,这样更安全.
你的榜样很直接.通过一些额外的工作,编译器显然可以看到你希望-1为短.尽管如此,所有边缘情况都伴随着隐式转换.如果为编译器添加一个规则来假设你想要的东西,你必须将它应用于每个不仅仅是一个的情况,而这就是它变得困难的地方.
作为一个注释,你应该查看Eric Lippert的博客,因为我知道他涵盖了为什么编译器不会做出这样的假设.