选择看起来像错误/缺失功能的重载时,C# 编译器出现奇怪的行为

2024-04-02

我最近发现 C# 编译器的一个有趣的行为。想象一下这样的界面:

public interface ILogger
{
   void Info(string operation, string details = null);
   void Info(string operation, object details = null);
}

现在如果我们这样做

logger.Info("Create")

编译器会抱怨他不知道选择哪个重载(不明确的调用...)。看起来很合乎逻辑,但是当你尝试这样做时:

logger.Info("Create", null)

它会突然毫无困难地弄清楚 null 是一个字符串。此外,寻找正确重载的行为似乎随着时间的推移而发生了变化,我在以前工作过的旧代码中发现了一个错误,但由于编译器决定使用另一个重载而停止工作。

所以我真的很想知道为什么 C# 在第二种情况下不会生成与第一种情况相同的错误。这样做似乎非常合乎逻辑,但它尝试将其解决为随机过载。

附:我不认为提供如此模糊的接口是件好事,也不建议这样做,但遗留就是遗留,必须维护:)


C# 6 中引入了一项重大更改,使重载解析变得更好。这里是 https://github.com/dotnet/roslyn/wiki/New-Language-Features-in-C%23-6#improved-overload-resolution与功能列表:

改进的过载分辨率

重载解析有许多小的改进,这可能会导致更多的事情按照您期望的方式工作。这些改进都与“更好”有关——编译器决定两个重载中哪一个对于给定参数更好的方式。

您可能会注意到这一点(或者更确切地说不再注意到问题!)的一个地方是在采用可为空值类型的重载之间进行选择时。另一个情况是当将方法组(而不是 lambda)传递给需要委托的重载时。细节不值得在这里展开——只是想让你知道!


但它会尝试将其解决为随机过载。

不,C# 不会随机选择重载,这种情况就是不明确的调用错误。 C# 选择更好的方法。请参阅 C# 规范中的第 7.5.3.2 节“更好的函数成员”:

7.5.3.2 更好的功能成员

否则,如果 MP 有更具体参数类型比MQ好,那么MP就比MQ好。令{R1, R2, …, RN}和{S1, S2, …, SN}代表MP和MQ的未实例化和未扩展的参数类型。如果对于每个参数,RX 不比 SX 更具体,并且对于至少一个参数,RX 比 SX 更具体,则 MP 的参数类型比 MQ 的参数类型更具体:

鉴于string比更具体object并且之间存在隐式强制转换null and string,那么谜团就解开了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

选择看起来像错误/缺失功能的重载时,C# 编译器出现奇怪的行为 的相关文章

随机推荐