2

考虑以下简单程序:

static class Program
{
  static void Main()
  {
  }

  static void Method(short? x)
  {
    const int y = 50; // note: is Int32, but is const and within Int16 range
    var z = x ?? y;   // note: var keyword used; IDE is confused about the type!
    TakeOnlyInt16(z);
    z.OnThisInt16();
  }

  static void TakeOnlyInt16(short a)
  {
  }
  static void OnThisInt16(this short a)
  {
  }
}

该程序绝对没有问题,并且可以毫无问题地编译。(您可以运行它,可能包括对Methodfrom的调用Main。)

但是,Visual Studio IDE对局部变量的类型有一个错误的印象z。它似乎认为它实际上是一个z(在 C# 中又名)。问题至少在三种情况下表现出来:Int32Int16short

  1. 当您“悬停”在(将鼠标悬停在)var关键字上时,它会Int32在工具提示中显示您。那是错的。

  2. 当您将文本(键盘)光标移动到语句TakeOnlyInt16(z);inside 内Method时,它会在该语句的左下角显示一个小提示,提供“为TakeOnlyInt16in生成方法存根Program”。这是错误的,因为该方法显然已经存在。但似乎认为已经存在的过载是错误的。shortint

  3. 当你z.在里面输入 (zed dot)Method时,成员就会Int32出现在intellisense中。请注意, 的重载CompareTo是由 声明的重载,Int32而不是由声明的重载Int16。此外,当您键入时,智能感知成员列表中缺少扩展方法z.

希望您在没有屏幕截图的情况下理解我的解释。

问题:这个错误来自哪里?它是众所周知的吗?它也在旧版本的 Visual Studio 中吗?

我在VS2013中试过这个。

4

3 回答 3

2

根据 C# 参考,空合并运算符 (??)

用于为可空值类型或引用类型定义默认值。如果操作数不为空,则返回左侧操作数;否则返回正确的操作数。

如果右手操作数是int,而左操作数(当不为空时)是short,则编译器必须在 和 之间进行int选择short。而且,因为short可以隐式转换为int(反之亦然),编译器正确地确定此表达式的结果是int类型的。

还是不服气?为什么不能反过来呢?嗯,让我们看看C# Language Specification 7.13 是怎么说的:

表达式的类型 a ?? b 取决于操作数上可用的隐式转换。按优先顺序,a 的类型??b 是 A0、A 或 B,其中 A 是 a 的类型(前提是 a 有类型),B 是 b 的类型(前提是 b 有类型),如果 A是可空类型,否则为 A。

如果您仍然想忽略“可用的隐式转换”部分,因为这可能会导致认为它应该是 A0(短),让我们继续阅读规范:

具体来说,一个?? b 处理如下:

• 如果 A 存在且不是可空类型或引用类型,则会发生编译时错误。

• 如果b 是动态表达式,则结果类型是动态的。在运行时,首先评估 a。如果 a 不为 null,则将 a 转换为动态,这将成为结果。否则,评估 b,这将成为结果。

• 否则,如果 A 存在并且是可为空的类型,并且存在从 b 到 A0 的隐式转换,则结果类型为 A0。在运行时,首先评估 a。如果 a 不为 null,则将 a 解包为类型 A0,这将成为结果。否则,b 被求值并转换为 A0 类型,这成为结果。 注意:情况并非如此,没有从 b (int) 到 A0 (short) 的转换

•否则,如果存在A 并且存在从b 到A 的隐式转换,则结果类型为A。在运行时,首先计算a。如果 a 不为空,则 a 成为结果。否则,b 被评估并转换为类型 A,这成为结果。

•否则,如果b 的类型为B,并且存在从a 到B 的隐式转换,则结果类型为B。在运行时,首先计算a。如果 a 不为空,则将 a 解包为 A0 类型(如果 A 存在且可为空)并转换为 B 类型,这将成为结果。否则, b 被评估并成为结果。 注意:情况就是这样

• 否则,a 和b 不兼容,并出现编译时错误。

所以,不,编译器不是错误的。你做出了错误的假设。

于 2013-11-26T17:32:05.103 回答
0

编译器看到:

const int y = 50; // note: is Int32, but is const and within Int16 range
var z = x ?? y;   // note: var keyword used; IDE is confused about the type!

并且知道那y是类型int,不管它是不是const。在这种情况下,z假定Int32它是较大的类型。

如果您正在寻找ztype short,请尝试:

const int y = 50; // note: is Int32, but is const and within Int16 range
var z = x ?? (short)y;   // note: var keyword used; IDE is confused about the type!
于 2013-11-26T15:03:54.877 回答
0

这是一个编译器优化,可能编辑器无法显示。

例如:

short? x = 44;
const int y = int.MaxValue;
var z = x ?? y;

var t = z.GetType(); //Int32

在这种情况下,编译器意识到z可能最终包含一个不适合 Int16 的值,因此它将声明z为 Int32。

在另一个示例中:

short? x = 44;
const int y = 33;
var z = x ?? y;

var t = z.GetType(); //Int16

编译器意识到z它将包含一个始终适合 Int16 的值,因此它将声明z为 Int16

于 2013-11-26T15:29:44.887 回答