Visual Studio IDE对var关键字的含义感到困惑

时间:2013-11-26 14:58:15

标签: c# visual-studio intellisense var implicit-typing

考虑以下简单程序:

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#中的a.k.a。Int16时,似乎认为shortvar。问题至少表现在三种情况:

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

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

  3. 当您在Method内输入Int32(zed dot)时,CompareTo的成员会出现在 intellisense 中。请注意Int32的重载是Int16声明的重载,而不是z.声明的重载。此外,当您键入{{1}}时,intellisense成员列表中缺少扩展方法。

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

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

    我在VS2013中试过这个。

3 个答案:

答案 0 :(得分:2)

According to C# reference,null-coalescing运算符(??)

  

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

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

还是不相信?为什么不能反过来呢?嗯,让我们看看C# Language Specification,7.13:

  

表达式的类型a ?? b取决于操作数上可用的隐式转换。按优先顺序排列,类型为?? b是A0,A或B,其中A是a的类型(假设a具有类型),B是b的类型(假设b具有类型),并且A0是A的基础类型,如果A是可以为空的类型,否则为A.

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

  

具体来说,?? b按如下方式处理:

     

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

     

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

     

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

     

•否则,如果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不兼容,并发生编译时错误。

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

答案 1 :(得分: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,因为它是更大的类型。

如果您希望z类型为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!

答案 2 :(得分: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

相关问题