为什么 C# 尝试转换 int?使用 Math.Min 时转换为字节?

Luk*_* Vo 6 .net c# nullable operation visual-studio

我刚刚发现了这个有趣的问题:

int done = 50;
int? total = 100;

var perc = done * 100 / total; // No problem

// Error: Argument 2: cannot convert from 'int?' to 'byte'
// Argument 1 is still int32
var perc2 = Math.Min(100, done * 100 / total);
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

起初,我的代码只需要第一个perc. 令人惊讶的是那里没有错误,因为我错过了null应该在那里的支票。直到后来我才发现我的错误:

在某些情况下,估计值total比应有的值要少,但百分比需要限制在 100,所以我添加了Math.Min. 现在我发现我错过了空检查,并且错误消息有点误导。

这里发生了什么?在这种情况下,C# 试图做什么?

Cod*_*ter 3

当您在代码中调用方法时,编译器将尝试根据您传递的参数列表(如果有)来查找该方法。采取这个方法:

public static void M(int i) { }
Run Code Online (Sandbox Code Playgroud)

您可以使用它来调用它M(42),一切都很好。当有多个候选人时:

public static void M(byte b) { }
public static void M(int i) { }
Run Code Online (Sandbox Code Playgroud)

编译器将应用“重载解析”来确定“适用的函数成员”,当超过一个时,编译器将计算重载的“更好性”以确定您打算调用的“更好的函数成员”。

在上面的示例中,M(42)选择int重载是因为 C# 中的无后缀数字文字默认为int,因此M(int)“更好”的重载也是如此。

(“引号”中的所有部分都可以在C# 语言规范 12.6.4 重载解析中查找。)

现在进入你的代码。

鉴于文字100可以存储在 abyte和 an int(然后是一些)中,并且您的第二个参数与任一重载都不匹配,编译器不知道您打算调用哪个重载。

它必须选择任何一个才能向您显示错误消息。在这种情况下,它似乎选择声明顺序中的第一个。

鉴于此代码:

public static void Main()
{
    int? i = null;
    M(100, i);
}

public static void M(int i, int i2) {}
public static void M(byte b, byte b2) {}
Run Code Online (Sandbox Code Playgroud)

它提到:

无法从“int”转换?到“int”

如果我们交换方法声明:

public static void M(byte b, byte b2) {}
public static void M(int i, int i2) {}
Run Code Online (Sandbox Code Playgroud)

它抱怨说:

无法从“int”转换?到“字节”