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

时间:2017-07-21 11:27:28

标签: c# compiler-errors overloading

我最近发现了一个有趣的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#在第二种情况下不会像第一种情况那样产生相同的错误。这样做似乎非常符合逻辑,但它会尝试将其解析为随机过载。

P.S。我不认为提供这种模糊的界面是好的,不建议这样做,但遗产是遗留的并且必须得到维护:)

1 个答案:

答案 0 :(得分:5)

C#6引入了一个突破性的变化,使得重载分辨率更好。 Here it is包含功能列表:

  

改进了重载分辨率

     

重载分辨率有许多小的改进,这可能会导致更多的东西按照你期望的方式工作。这些改进都与“更好”有关 - 编译器决定哪两个重载对于给定参数更好。

     

您可能会注意到这一点(或者更确切地说是停止注意问题!)的一个地方是在选择采用可空值类型的重载时。另一种方法是将方法组(而不是lambdas)传递给期望委托的重载。细节不值得在这里扩展 - 只是想让你知道!

  

但它试图将其解析为随机过载。

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

  

7.5.3.2更好的功能成员

     

否则,如果MP具有更具体的参数类型而不是MQ,则MP优于MQ。设{R1,R2,...,RN}和{S1,S2,...,SN}表示MP和MQ的未实例化和未展开的参数类型。 MP的参数类型比MQ更具体,如果对于每个参数,RX的特定性不低于SX,并且对于至少一个参数,RX比SX更具体:

鉴于stringobject更具体,并且在nullstring之间存在隐式演员,那么这个谜就解决了。