与可选参数冲突的重载方法

Posted

技术标签:

【中文标题】与可选参数冲突的重载方法【英文标题】:Conflicting overloaded methods with optional parameters 【发布时间】:2011-02-10 02:12:15 【问题描述】:

我有两个重载方法,一个带有可选参数。

void foo(string a)     
void foo(string a, int b = 0)    

现在我打电话:

 foo("abc");

有趣的是,第一个重载被调用了。 为什么不将可选值设置为零的第二个重载?

说实话,我本以为编译器会带来错误,至少是警告,以避免无意执行错误的方法。

这种行为的原因是什么?为什么 C# 团队会这样定义它?

【问题讨论】:

这正是导致潜在错误的糟糕语言设计。内部人员也可以很容易地利用它进行企业间谍活动。我希望他们已经阻止语言允许这样做。 【参考方案1】:

想象一下,如果情况正好相反。你有一个应用程序。它有一个方法:

void foo(string a)      

一切正常。现在,您想再添加一个带有可选参数的重载:

void foo(string a, int b = 0)    

轰隆隆!所有方法调用都转到新方法。无论你想要与否。添加方法重载可能会导致整个应用程序发生错误的方法调用。

在我看来,在这种情况下,您将有更多机会破解您(或其他人)的代码。

此外,OptionalAttribute 在 C# 中被忽略,直到 4.0 版,但您可以使用它。有些人确实在 C# 代码中使用它来支持与其他语言(例如 Visual Basic)或 COM 互操作的某些互操作性场景。现在 C# 将它用于可选参数。添加警告/错误可能会为这些应用程序带来重大更改。

可能还有其他一些原因,但这只是我首先想到的。

【讨论】:

它应该显示编译器错误或代码分析警告。 @Locutus 您似乎没有阅读亚历山德拉回答的倒数第二段。【参考方案2】:

来自MSDN:

如果两个候选者被判断为同样好,则优先考虑没有可选参数的候选者,在调用中省略了这些参数。这是由于参数较少的候选者普遍偏好重载解决方案的结果。

【讨论】:

【参考方案3】:

不需要自动填充任何可选参数的重载优于需要自动填充的重载。但是,在自动填充一个参数和填充多个参数之间没有这样的偏好 - 例如,这将导致编译时错误:

void Foo(int x, int y = 0, int z = 0) 
void Foo(int x, int y = 0) 
...
Foo(5);

注意 Foo(5, 5) 会被解析为第二种方法,因为这样就不需要自动填写任何可选参数了。

来自 C# 4 规范的第 7.5.3.2 节:

否则如果 MP 的所有参数都有 一个相应的论点,而 默认参数需要是 替换为至少一个可选的 MQ中的参数然后MP优于 MQ。

老实说,我认为在大多数情况下,这是大多数人所期望的行为。当您将基类方法引入混合时会变得很奇怪,但情况总是如此。

【讨论】:

感谢您的回答。还有一个问题:他们为什么要这样定义?是否存在可选参数的重载有意义的场景?它永远不会用默认值调用,对吧?但它可能会导致不必要的错误。我仍然认为编译器应该至少给出一个警告。还有其他一些例子,开发人员必须明确告诉编译器他知道自己在做什么。例如,如果方法中的参数声明为 ref,我也需要在方法调用中显式使用 ref 关键字;否则无法编译。 @Thomas:恐怕我没有任何答案——尽管 Eric Lippert 可能。我不希望您必须向调用代码添加任何 更多 包袱 - 毕竟,默认参数的原因正是为了 减少 您的代码量需要。

以上是关于与可选参数冲突的重载方法的主要内容,如果未能解决你的问题,请参考以下文章

函数重载与可选参数

Swift:如何将 for-in 循环与可选参数一起使用?

argparse 必需参数列表与可选参数列表竞争

在 C# 4.0 中是不是应该使用重载或可选参数声明方法?

重载的方法在 Resharper 中给出“带有可选参数的方法被重载隐藏”警告

可选参数后的重载