为什么在使用Math.Min时,C#会尝试将int转换为byte?

6

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

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);

enter image description here

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

然后有一些情况下,估计值total比应该的要小,但百分比需要被限制在100,所以我添加了Math.Min。现在我发现我错过了一个空值检查,而且错误信息有点误导人。

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


6
没有针对 int, int?Min 重载操作,因此您需要使用 C# 中重载方法的复杂规则来获取“最佳匹配”。毫无疑问,通过仔细解析标准,可以清楚地了解为什么第一个参数被解析为 byte 而不是其他任何整数类型,但这是标准中最困难的部分,所以我相信编译器在那里做正确的事情。 - Jeroen Mostert
1
perc 的类型是 int?,所以没问题。但传递给 Math.Min() 的值必须是 int,而不是 int?,所以这样行不通。 - Matthew Watson
2
@MatthewWatson 这是我认为最好的解释。 我没有注意到 perc 也是一个 int?(即 Nullable<int>,这是完全不同的 int 类型)。 - Luke Vo
2
@JeroenMostert是正确的,因为参数是int?,它可以根据需要进行解析。奇怪的是,如果我将光标悬停在第一个参数上,它会显示为int32,但它却选择了第一个重载(即byte,byte)。 - Luke Vo
1
我也在想为什么int?的除法被接受(并且应该产生null)...我从未注意到,但是对我来说这似乎非常危险。 - Mario Vernari
显示剩余4条评论
2个回答

4

您正在使用 Nullable 类型。这是一种包装结构的类型,它不能为 null。要获取值,您需要引用它:

var perc2 = Math.Min(100, done * 100 / total.Value);

问题不在于如何解决即时错误(根据total的来源,.Value可能会抛出异常),而是为什么编译器会表现出这种行为。 - CodeCaster

3
当你在代码中调用一个方法时,编译器会尝试找到该方法,前提是你传递了参数列表(如果有的话)。以这个方法为例:
public static void M(int i) { }

你可以使用M(42)进行调用,一切都很好。当有多个候选项时:

public static void M(byte b) { }
public static void M(int i) { }

编译器将应用“重载解析”来确定“适用的函数成员”,当存在多个函数成员时,编译器将计算重载的“优劣”以确定您打算调用的“更好的函数成员”。
在上面的示例中,M(42),选择了int重载,因为在C#中,非带后缀的数值字面量默认为int,所以M(int)是“更好的”重载。
(可以在C#语言规范,12.6.4 重载解析中查找所有带“引号”的部分。)
现在让我们看看您的代码。
给定字面值100可以存储在byteint(以及其他类型)中,而且您的第二个参数与任何一个重载都不匹配,编译器无法知道您打算调用哪个重载。
它必须选择其中一个来向您呈现错误消息。在这种情况下,它似乎选择了声明顺序中的第一个。
给定此代码:
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) {}

它提到:

无法将“int?”转换为“int”

如果我们交换方法声明:

public static void M(byte b, byte b2) {}
public static void M(int i, int i2) {}

它报错了:

无法将'int?'转换为'byte'


1
在这种情况下,编译器似乎只是采用“由于没有最佳匹配的重载,我将选择任意一个,你不能抱怨”的思路。规范仅表示“如果没有恰好一个函数成员比所有其他函数成员更好,则函数成员调用是模糊的,并且会发生绑定时错误”,而不对错误应该如何进行约束。我还没有通过规则来确定是否确实没有更好的匹配,但我怀疑情况是这样的。 - Jeroen Mostert
谢谢。这就是我问这个问题时正在寻找的答案。只是一个小问题,你怎么确定另一个(现已删除)答案是ChatGPT?我因为句子中的“奇怪”而怀疑它,但我们能如此确定吗? - Luke Vo
1
@Luke,我现在已经识别并标记了十几个。这只是一种直觉,但它是相当可识别的写作风格。与他们先前的回答不同,它也是完美的英语。 - CodeCaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接