我最近发现了一个有趣的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。我不认为提供这种模糊的界面是好的,不建议这样做,但遗产是遗留的并且必须得到维护:)
答案 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更具体:
鉴于string
比object
更具体,并且在null
和string
之间存在隐式演员,那么这个谜就解决了。