为什么我必须在三元表达式中对int进行类型转换?

可能重复:
条件运算符不能隐式转换?

我遇到了一种奇怪的情况,想知道我为什么要这样做。 我正在使用.NET 3.5。

这有效:

short foo; if (isValid) foo = -1; else foo = getFoo(); 

这不起作用:

 short foo; foo = isValid ? -1 : getFoo(); 

我要打字-1:

 short foo; foo = isValid ? (short)-1 : getFoo(); 

三元表达式有何不同? 它认为-1是一个需要被转换为short的int。 但为什么?

一些东西。

首先,条件运算符是三元运算符,而不是第三运算符 。

其次,我注意到在您的代码示例中,两个代码示例是等效的:

 short foo; if (isValid) foo = -1; else getFoo(); 

是不一样的

 short foo = isValid ? (short)-1 : getFoo(); 

如果isValid为false,前者将foo取消分配。 无论isValid的值如何,后者都会赋予foo。

我认为你的意思

 short foo; if (isValid) foo = -1; else foo = getFoo(); 

而且,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); 

我不认为你会期望重载决议说“好吧,我通常选择M(int),因为-1是一个int,但是不,我会选择M(短)而不是因为其他分配赢了”工作。“ 重载决议不知道结果的去向 。 它的工作是根据给定的参数计算出正确的重载,而不是基于调用的上下文。

确定条件表达式的类型的方式相同。 我们不看它的类型,我们看一下表达式中的类型。

好的,所以我们已经确定将这个分配给short的事实与确定表达式的类型无关。 但这仍然留下了一个问题“为什么条件表达式的类型是int而不是short?”

这是一个非常好的问题。 我们去看看规格。

?:运算符的第二个和第三个操作数x和y控制条件表达式的类型。

如果类型为X且y具有类型Y,则:

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

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

否则,不能确定表达式类型,并发生编译时错误。

在这种情况下,操作数都有一个类型。 (关于“如果x有一个类型……”的措辞是针对那里你有null或lambda的情况;那些没有类型!)第一个操作数是int类型,第二个操作数是类型短。

隐式转换从short到int,但不是从int到short。 因此,条件表达式的类型为int,不能将其赋值为short。

现在,可以说这个算法并不尽如人意。 我们可以使算法复杂化以处理存在两种可能的“候选”类型的所有情况 – 在这种情况下,int和short都是合理的候选者,因为当被视为特定表达式时,两个分支都可以转换为int和short两者,而不仅仅是有类型 。 在这种情况下,我们可以说两种类型中较小的一种是首选类型。

(有时候在C#中我们说两种类型中更通用的是更好的类型,但是在这种情况下你会希望我们选择更具体的类型。不幸的是,这种语言在这个特定的设计方面并不一致;我个人宁愿我们总是选择更具体的,但有类型推断场景,现在这将是一个突破性的变化。)

我在2006年考虑过这样做。在设计LINQ如何处理有多种类型可供选择的情况以及必须选择“最佳”的行为时,我们注意到条件运算符已经必须解决这个问题,并且此外,在C#2中,它实际上并未根据规范实施。 关于这一点存在很长时间的争论,我们最终对条件运算符的规范进行了一些小的改动,使其更符合其实现的(和期望的)行为。 然而,当有几个可供选择时,我们决定不对调整算法进行更大的改变,以使用两种可能类型中较小的一种。

关于这个问题的一些想法,请参阅2006年的post:

  • 类型推断困境,第一部分

  • 类型推断困境,第二部分

  • 类型推断困境,第三部分

因为-1默认是一个整数。 编译器告诉您必须明确告诉它要做什么,而不是让编译器对您想要做的事情做出假设,这样更安全。

你的榜样很直接。 通过一些额外的工作,编译器显然可以看到你希望-1为短。 有一些边缘情况与隐式转换一起使用并不是那么简单。 如果为编译器添加规则以假设您想要的内容,则必须将其应用于每个案例而不仅仅是一个案例,这是困难的地方。

作为一个注释,你应该查看Eric Lippert的博客,因为我知道他涵盖了为什么编译器不做出这样的假设。

应用于intshort条件运算符的类型为int ; 编译器不会从您为其指定的类型推断表达式的类型。

您不能将此short表达式隐式转换为int

条件运算符强制两个可能的结果表达式具有相同的类型。 在这种情况下,左侧是int ,右侧是getPoo方法返回的getPoo 。 由于将short转换为int始终是安全的,因此编译器会选择操作的结果为int

因此,结果将是一个int赋值给short ,这就是为什么你需要显式地将它转换为short。

如果明确使用if / else方法,则会将一个文字整数分配给short,这允许编译器validation文字整数是否安全地分配给short而不需要显式强制转换。

有关内部解释,请查看:

演员不遵守分配法

Interesting Posts