我正在测试一个简单的程序来重载整数参数:
class Program
{
public static void Foo(Int16 value)
{
Console.WriteLine("Int16");
}
public static void Foo(Int32 value)
{
Console.WriteLine("Int32");
}
public static void Foo(Int64 value)
{
Console.WriteLine("Int64");
}
static void Main(string[] args)
{
Foo(10);
}
}
现在我知道这些类型的容量是这样的:
Type Capacity
Int16 -- (-32,768 to +32,767)
Int32 -- (-2,147,483,648 to +2,147,483,647)
Int64 -- (-9,223,372,036,854,775,808 to +9,223,372,036,854,775,807)
现在 Foo(10)
调用 Int32
重载。为什么? 10 的值不能放入 Int16
中吗?
更让我困惑的是,当我删除 Int32
重载时,调用了 Int16
重载。这是为什么?
如果在没有后缀的代码中指定整数文字,根据 C# 规范第 2.4.4.2 章“整数文字”,它获得类型 int
,uint
或 long
,具体取决于哪种类型可以保存其值。
因此您的 10
是一个 Int32
,并且没有任何改变。
现在有趣的是,如果你删除 Int32
重载,10
仍然是一个 Int32
,但是具有最小类型的重载可以保存正在调用的值,在本例中为 Int16
。
我无法在指定的位置快速找到它,但您可以在生成的 IL 中看到它:
.method public hidebysig static void Main(string[] args) cil managed
{
//
.maxstack 8
IL_0000: nop
IL_0001: ldc.i4.s 10
IL_0003: call void Program::Foo(int16)
IL_0008: nop
IL_0009: ret
} // end of method Program::Main
编译器可以这样做,因为 10
是一个常量,因此信息在编译时是已知的(而不是如果它是一个变量)。作为 Eric Lippert states it:
It is implicitly convertible to all the built-in numeric types. Therefore when asked to make a choice of the best overload, overload resolution will first choose the exact match -- int
-- if available. If not, then it will choose the unique most specific type available, if there is one. short
is more specific than long
because all shorts are convertible to long but not all longs are convertible to short.
另见: