为什么我必须在三元表达式中打字int? [英] Why do I have to typecast an int in a ternary expression?

查看:147
本文介绍了为什么我必须在三元表达式中打字int?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


可能重复:

条件运算符不能隐式转换?


一个特殊的情况,想知道为什么我必须这样做。我使用 .NET 3.5。



这样工作:

  short foo; 

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

这不起作用:

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

我必须typecast -1:

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

三元表达式有什么不同?它认为-1是一个int,需要投入一个短。但为什么?


b

$ p

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



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

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

不同

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

如果isValid为false,则前者将foo取消赋值。



我假设你的意思是

 

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

此外,getFoo()返回short。


$ b b

问题是为什么没有类型转换的条件运算符中的转换是非法的,但是if语句是合法的。



这是合法的if语句因为规范6.1.9节规定:


int类型的常量表达式可以转换为类型sbyte,byte ,short,ushort,uint或ulong,前提是常量表达式的值在目标类型的范围内。


-1是一个int类型的常量表达式,它在short的范围内,所以可以隐式转换为short。



那么为什么条件表达式形式为bogus?



我们必须清楚地建立的第一件事是规则,条件表达式的类型是从其内容而不是从上下文。分配右侧的表达式类型不取决于分配给它的内容!假设你有

  short M(short x){...} 
int M(int x){。 ..}

short y = M(-1);

我不认为你会期望重载分辨率说 M(int),因为-1是一个int,但没有,我会选择M(短),否则分配将无法工作。过载解析不知道结果的来源



确定条件表达式的类型是否符合条件表达式的工作原理同样的方式。我们不看看它的类型,我们看看表达式中的类型。



确定,所以我们已经确定,这是被分配到短语与确定表达式的类型无关。但这仍然留下这个问题为什么条件表达式的类型是int而不是短?



这是一个很好的问题。让我们去规范。


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



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



如果存在从X到



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



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


在这种情况下,操作数都有一个类型。 (关于如果x有一个类型...的语句是对于你有空或一个lambda在那里的情况;那些没有类型!)第一个操作数是类型int,第二个是类型short。



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



现在,可以说这个算法不是那么好。我们可以大大复杂的算法来处理所有的情况,其中有两种可能的候选类型 - 在这种情况下,int和short都是似乎合理的候选人,因为两个分支可以转换为int和短当考虑为特定表达式,而不是简单地具有类型。在这种情况下,两种类型的较小是首选类型。



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



我考虑在2006年回来。在设计LINQ交易的行为在有多种类型可供选择的情况下,一个必须被选为最好的,我们注意到条件运算符已经不得不解决这个问题,此外,在C#2它没有实际实现根据规范。有一个长期的争论,我们最终对条件运算符的规范做了一些小改动,使其更符合其实现(和期望的)行为。然而,我们决定不采取更大的破坏性的改变算法使用两种可能的类型中较小的,当有几个可以选择。



对于这个问题,查看我从2006年以来的帖子:




Possible Duplicate:
Conditional operator cannot cast implicitly?

I have run into a peculiar situation and want to know why I have to do it. I'm using .NET 3.5.

This works:

short foo;

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

This does not work:

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

I have to typecast -1:

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

What does the ternary expression do differently? It considers the -1 to be an int that needs to be cast into a short. But why?

解决方案

A few things.

First off, the conditional operator is a ternary operator, not a tertiary operator.

Second, I note that in your code samples the two code samples which are intended to be equivalent are not:

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

is not the same as

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

The former leaves foo unassigned if isValid is false. The latter assigns foo regardless of the value of isValid.

I assume that you meant

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

and that furthermore, getFoo() returns short.

The question is why the conversion in the conditional operator without the type cast is illegal but in the consequence of the if statement is legal.

It is legal in the if statement because section 6.1.9 of the specification states:

A constant-expression of type int can be converted to type sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant-expression is within the range of the destination type.

-1 is a constant expression of type int that is in the range of short, so it can be converted to short implicitly.

So why is the conditional expression form bogus?

The first thing we have to establish clearly is the rule that the type of the conditional expression is determined from its contents, not from its context. The type of the expression on the right side of an assignment does not depend on what it is being assigned to! Suppose you had

short M(short x){...}
int M(int x){...}

short y = M(-1);

I don't think you'd expect overload resolution to say "well, I'd normally pick M(int) because -1 is an int, but no, I'll pick M(short) instead because otherwise the assignment won't work." Overload resolution doesn't know anything about where the result is going. It's job is to work out what the right overload is based on the arguments given, not based on the context of the call.

Determining the type of the conditional expression works the same way. We don't look at the type its going to, we look at the types that are in the expression.

OK, so we have established that the fact that this is being assigned to short is irrelevant for determining the type of the expression. But that still leaves the question "Why is the type of the conditional expression int rather than short?"

That is a very good question. Let's go to the spec.

The second and third operands, x and y, of the ?: operator control the type of the conditional expression.

If has type X and y has type Y then:

If an implicit conversion exists from X to Y, but not from Y to X, then Y is the type of the conditional expression.

If an implicit conversion exists from Y to X, but not from X to Y, then X is the type of the conditional expression.

Otherwise, no expression type can be determined, and a compile-time error occurs.

In this case the operands both have a type. (The verbiage in there about "if x has a type..." is for the case where you have null or a lambda in there; those don't have types!) The first operand is of type int, the second is of type short.

An implicit conversion exists from short to int, but not from int to short. Therefore the type of the conditional expression is int, which cannot be assigned to short.

Now, one could say that this algorithm is not as good as it could be. We could greatly complicate the algorithm to deal with all the cases where there were two possible "candidate" types -- in this case, int and short are both plausible candidates because both branches are convertible to both int and short when considered as specific expressions, rather than simply as having types. We could say in that case that the smaller of the two types was the preferred type.

(Sometimes in C# we say that the more general of two types is the better type, but in this case you would want us to pick the more specific. The language is not consistent in this particular design aspect, unfortunately; I personally would rather we always choose the more specific, but there are type inference scenarios where that would be a breaking change now.)

I considered doing that back in 2006. When designing the behaviour of how LINQ deals with situations where there are multiple types to choose from and one must be picked as "the best" we noticed that the conditional operator already had to solve this problem, and that furthermore, in C# 2 it was not actually implemented according to spec. There was a long debate about this and we ended up making some minor changes to the specification for the conditional operator to bring it more into line with its implemented (and desired) behaviour. However we decided to not take the larger breaking change of tweaking the algorithm to use the smaller of two possible types when there were several to choose from.

For some musings on this problem, see my posts from 2006 on it:

这篇关于为什么我必须在三元表达式中打字int?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆