为什么这个强制类型转换是多余的?

74

我有一个带有以下重载的方法:

string Call(string function, Dictionary<string, object> parameters, object body)
string Call(string function, Dictionary<string, object> parameters, JObject body)

现在我添加了另一个重载函数:

string Call(string function)
{
    return Call(function, null, (JObject) null);
}

我向 JObject 添加了一个强制转换以使编译器知道应该使用哪个重载。但是 Visual Studio 告诉我这个强制转换是多余的。但是如果没有这个强制转换,为什么我的调用不会产生歧义?


19
即使编译器不会有歧义,我也会保留强制类型转换,因为它可能会让阅读代码的人感到含糊不清。 - Alex
5
@jean 不是那个原因。我在告诉编译器使用哪个重载方法。而且,使用哪个方法重载确实很重要,因为它们可能有完全不同的实现。null 就是 null,但是这里的强制转换是一个提示,指示应该使用哪个方法重载。 - fero
1
@jean,恐怕这又是错误的。强制类型转换只是多余的,因为编译器仍将使用 JObject 重载,即使我不将其强制转换为 JObject,因为它使用与参数匹配的最具体的重载,而 null 可以匹配任何东西,JObjectobject 更具体。详细解释请见Jon Skeet的回答。 - fero
1个回答

98

但是,为什么没有强制转换,我的调用不会引起歧义呢?

这是因为带有JObject参数的重载比带有object参数的重载更“好”... 因为从nullJObject的转换比从nullobject的转换更“好”。

JObjectobject更具体,因为存在从JObjectobject的隐式转换,而反之则不存在。

如果第一个方法的最后一个参数是string(例如),那么两个重载都不会比另一个更好,调用将会需要强制转换来消除歧义。

请参见C# 5规范的7.5.3节以了解所有复杂细节。特别是7.5.3.5节(“更好的转换目标”)在此处很重要。


8
即使在当前的类中不需要使用类型转换(cast),如果调用代码没有进行空引用的类型转换,则会使得代码变得非常脆弱。加入任何一个额外的引用类型重载几乎都会破坏那些没有进行类型转换的调用代码。在存在任何可能出现模糊性的情况下,我不会认为将空引用进行类型转换是“多余”的,在某些情况下甚至可以认为某个特定的重载规则更好,但实际上它是否更好还远非显而易见。 - supercat
1
顺便说一句,我长期以来认为,具有重载功能的语言如果能够使用属性或其他方式来指定某些重载应被视为“首选”,而其他重载则仅作为“后备”,那么将会大大受益;我还认为,如果一个重载可以指定一个参数类型为null,那将会很有帮助。你知道是否有任何这样做的语言吗? - supercat
2
@supercat:C++11及以后引入了nullptr_t,可用作参数类型。但空指针字面值仍然可以隐式转换为int和对象指针类型,因此对于重载分辨率并没有太大帮助。在C++(所有版本)中,尾随可变参数列表(...)非常适合使特定的重载不那么优先。 - Ben Voigt
@JonSkeet:我想知道为什么语言通常不允许优先机制?我认为允许程序员对重载进行优先排序(并在模棱两可的情况下要求优先排序)比试图制定和实施规则更容易,这些规则通常会选择在几种情况下最有用的重载,并且还可以缓解“脆弱基类”问题。 - supercat
8
如果你真的想手动指定重载函数,为什么不直接创建一个新的独一无二的命名函数呢? - Superbest
显示剩余5条评论

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