考虑以下简单程序:
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
生成方法存根” 。这是错误的,因为该方法显然已经存在。但是似乎认为已经存在的过载是错误的。 short
和int
。当您在
z.
中键入Method
(带点号)时,Int32
的成员会出现智能提示。请注意,CompareTo
的重载是Int32
声明的重载,而不是Int16
声明的重载。另外,键入z.
时,智能感知成员列表中缺少扩展方法。希望您能理解我的解释而没有截图。
问题:此错误来自何处?众所周知吗?在旧版本的Visual Studio中也是如此吗?
我在VS2013中尝试过。
最佳答案
According to C# reference,空值运算符(??)
用于为可为空的值类型定义默认值,或
参考类型。如果操作数为,则返回左侧的操作数
不为空;否则返回正确的操作数。
如果右操作数为int
,而左操作数(不为null)为short
,则编译器必须在int
和short
之间进行选择。并且,由于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/