考虑以下简单程序:

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)
  {
  }
}


该程序绝对没有错,并且编译没有问题。
(并且您可以运行它,可能包括从Method调用Main的过程。)

但是,Visual Studio IDE对局部变量z的类型有错误的印象。似乎认为z实际上是Int32(在C#中又称为Int16)中是short。该问题至少在以下三种情况下显示:


当您将鼠标悬停在(按住鼠标)var关键字时,它会在工具提示中向您显示Int32。那是错的。
当您将文本(键盘)光标移动到TakeOnlyInt16(z);内的语句Method内时,该语句的左下角会显示一个小提示,提示您“在TakeOnlyInt16中为Program生成方法存根” 。这是错误的,因为该方法显然已经存在。但是似乎认为已经存在的过载是错误的。 shortint
当您在z.中键入Method(带点号)时,Int32的成员会出现智能提示。请注意,CompareTo的重载是Int32声明的重载,而不是Int16声明的重载。另外,键入z.时,智能感知成员列表中缺少扩展方法。


希望您能理解我的解释而没有截图。

问题:此错误来自何处?众所周知吗?在旧版本的Visual Studio中也是如此吗?

我在VS2013中尝试过。

最佳答案

According to C# reference,空值运算符(??)


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


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

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


  表达式的类型b取决于操作数上可用的隐式转换。按照优先顺序,类型为??。 b是A0,A或B,其中A是a的类型(假设a具有类型),B是b的类型(假设b具有类型),并且A0是A的基础类型(如果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不为null,则a为结果。否则,将对b求值并将其转换为类型A,这将成为结果。
  
  •否则,如果b具有类型B,并且存在从a到B的隐式转换,则结果类型为B。在运行时,首先对a求值。如果a不为null,则将a展开为A0类型(如果A存在并且可以为空)并转换为B类型,这将成为结果。否则,将评估b并成为结果。
  注意:就是这种情况
  
  •否则,a和b不兼容,并且发生编译时错误。


因此,不,编译器不是错误的。您做错了一个假设。

关于c# - Visual Studio IDE对var关键字的含义感到困惑,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20220526/

10-09 19:19