使用整数参数重载:Int16,Int32,Int64始终调用Int32?

时间:2017-03-03 06:52:08

标签: c#

我正在测试一个简单的程序来重载整数参数:

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重载。那是为什么?

2 个答案:

答案 0 :(得分:4)

如果在没有后缀的代码中指定整数文字,根据C#规范第2.4.4.2节“整数文字”,它会得到类型intuint或{{1} },取决于哪种类型可以保持其值。

所以你的long10,所以没有任何改变。

现在有趣的是,如果删除Int32重载,Int32仍然是10,但是可以调用可以容纳该值的最小类型的重载,在这种情况下Int32

我无法快速找到指定的位置,但您可以在生成的IL中看到它:

Int16

编译器可以这样做,因为.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 是一个常量,因此信息在编译时是已知的(而不是它是一个变量)。正如Eric Lippert states it

  

它可以隐式转换为所有内置数字类型。因此,当要求选择最佳过载时,重载决策将首先选择完全匹配 - 10 - 如果可用。如果没有,那么它将选择唯一最具体的类型(如果有的话)。 intshort更具体,因为所有空头都可以转换为多头,但并非所有多头都可以转换为空头。

另见:

答案 1 :(得分:2)

解释了默认映射here

正如Hans Passant所说,解除Int32重载时发生的事情已解释为here

  

Foo.Bar(10)表示10是const int而不是int。现在有道理。 const int达到编译器可以将int固定为最小的大小,即[{short = Int16],如果是10. int将获得自己的大小或更大,即long [= Int64] - basarat

_

  

推理是:一个常量整数可以隐式转换为它适合的任何整数类型,因此所有三种方法都适用。我们现在必须确定三种适用方法中哪一种最好。它是具有最具体参数类型的那个。类型X比类型Y更具体,如果“所有X都可以转换为Y而不是所有Y都可以转换为X”。也就是说,长颈鹿比动物更具特异性,因为所有长颈鹿都是动物,但反之亦然。 [short = Int16]比long [= Int64]更具体,因此获胜。 - Eric Lippert

Eric可能知道这一点,he was on the Microsoft C# language development team ......