代码之家  ›  专栏  ›  技术社区  ›  jsmith

为什么要在三元表达式中键入int[[副本]

  •  3
  • jsmith  · 技术社区  · 14 年前

    可能重复:
    Conditional operator cannot cast implicitly?

    我遇到了一个特殊的情况,想知道我为什么要这么做。我在用 .NET

    这样做有效:

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

    这不起作用:

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

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

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

    4 回复  |  直到 7 年前
        1
  •  11
  •   Glorfindel Doug L.    3 年前

    一些事情。

    首先,条件运算符是 ternary operator, not a tertiary operator .

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

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

    不等于

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

    如果isValid为false,则前者使foo未赋值。后者分配foo,而不管isValid的值是多少。

    我想你是说

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

    而且,getFoo()返回short。

    由于规范第6.1.9节规定:

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

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

    那么为什么条件表达式形式是假的呢?

    我们首先要明确的是,条件表达式的类型是由它的 目录 上下文 . 赋值右侧表达式的类型不取决于它被赋给什么!假设你有

    short M(short x){...}
    int M(int x){...}
    
    short y = M(-1);
    

    结果如何 . 它的工作是根据给定的参数,而不是根据调用的上下文来确定正确的重载是什么。

    这是一个很好的问题。我们去看看说明书吧。

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

    如果类型为X,y为y,则:

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

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

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

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

    现在,有人可能会说这个算法并没有它所能做到的那么好。我们可以极大地使算法复杂化,以处理存在两种可能的“候选”类型的所有情况——在本例中,int和short都是合理的候选,因为这两个分支都可以转换为int和short 当被认为是特定的表达式时,而不是简单地认为有类型 . 在这种情况下,我们可以说 较小

    (有时在C中,我们说 更一般

    我早在2006年就考虑过这样做。在设计LINQ如何处理有多种类型可供选择并且必须选择一种类型作为“最佳”的情况时,我们注意到条件运算符已经必须解决这个问题,而且,在C#2中,它实际上并没有按照规范来实现。对此有一个长期的争论,我们最终对条件运算符的规范做了一些小的修改,使其更符合其实现的(和期望的)行为。然而,我们决定不采取更大的突破性改变调整算法使用两个可能的类型较小时,有几个选择。

    关于这个问题的一些思考,请参阅我2006年的文章:

        2
  •  6
  •   Glorfindel Doug L.    3 年前

    因为-1在默认情况下是一个整数。编译器告诉您必须显式地告诉它要做什么要比编译器假设您要做什么安全得多。

    你的例子很直接。通过一点额外的工作,编译器显然可以看到您希望-1是一个短的。不过,隐式转换所涉及的所有边缘情况都不是那么简单。如果您为编译器添加了一个规则来对您想要的内容进行假设,那么您必须将它应用于每一个案例,而不仅仅是一个案例,而这正是它变得困难的地方。

    请注意,您应该退房 Eric Lippert's 据我所知,他在博客中讲述了编译器为什么不做这样的假设。

        3
  •  1
  •   SLaks    14 年前

    应用于函数的条件运算符 int 和一个 short ; 编译器不会从指定给表达式的类型推断表达式的类型。

    不能隐式地强制转换此 短的 内景 .

        4
  •  0
  •   Glorfindel Doug L.    3 年前

    int 右边是一个 short 退回人 getPoo 内景 编译器选择操作的结果是 内景

    因此结果将是一个 这就是为什么你需要显式地把它转换成一个空头。

    如果显式使用If/else方法,则将向short赋值一个文本整数,这样编译器就可以验证文本整数是否安全地赋值给short,而无需显式转换。

    有关内部解释,请看:

    Cast operators do not obey the distributive law