为什么C#允许通过可选参数进行模糊函数调用?

Ada*_*win 18 c# overloading ambiguity optional-arguments

我今天遇到了这个,我很惊讶我之前没有注意到它.给出一个简单的C#程序,类似于以下内容:

public class Program
{
    public static void Main(string[] args)
    {
        Method(); // Called the method with no arguments.
        Method("a string"); // Called the method with a string.

        Console.ReadLine();
    }

    public static void Method()
    {
        Console.WriteLine("Called the method with no arguments.");
    }

    public static void Method(string aString = "a string")
    {
        Console.WriteLine("Called the method with a string.");
    }
}
Run Code Online (Sandbox Code Playgroud)

您将获得每个方法调用的注释中显示的输出.

我理解为什么编译器会选择它所做的重载,但为什么首先允许这样做呢?我不是在问什么是重载决策规则,我理解这些规则,但我想知道是否存在技术上的原因,为什么编译器允许基本上具有相同签名的两个重载?

据我所知,一个带有签名的函数重载只是通过另外一个可选参数与另一个重载不同,只提供了如果只需要参数(和所有前面的参数).

它所做的一件事是让程序员(可能没有给予足够的重视)认为他们正在调用与他们实际存在的不同的重载.

我想这是一个相当罕见的情况下,以及为什么这是允许的可能只是因为它根本不值得的复杂性,以禁止它的答案,但有另一个原因,C#允许函数重载从其他人的不同仅通过有一个附加的可选争论?

Eri*_*ert 14

他的观点是Eric Lippert可以得到一个答案引导我到这个https://meta.stackoverflow.com/a/323382/1880663,这听起来像我的问题只会让他烦恼.我会尝试改写它以使我更清楚我在询问语言设计,并且我不是在寻找规范参考

我很感激!我很高兴谈论语言设计; 令我恼火的是,当提问者非常不清楚实际上会满足他们的要求时,我会浪费时间.我认为你的问题清楚明了.


汉斯发表的对你的问题的评论是正确的.语言设计团队非常了解您提出的问题,这远远不是可选/命名参数创建的唯一潜在歧义.我们长期考虑了很多场景,并尽可能仔细地设计了该功能,以减轻潜在的问题.

所有设计过程都是竞争设计原则之间妥协的结果.显然,有许多论点需要与重要的设计,实现和测试成本以及混淆,错误等形式的用户成本之间的平衡,以及意外构造模糊性等问题.你指出一个.

我不打算重复几十个小时的辩论; 让我给你高分.

正如Hans所说,该功能的主要推动方案是受欢迎的需求,特别是来自使用C#和Office的开发人员.(并且完全披露,作为在我加入C#团队之前为Word和Excel编写C#编程模型的团队成员,我实际上是第一个要求它的人;具有讽刺意味的是,我必须实现这个困难的功能几年之后并没有丢失在我身上.)Office对象模型被设计为从Visual Basic中使用,Visual Basic是一种长期具有可选/命名参数支持的语言.

就明显的功能而言,C#4可能看起来像是一个"瘦"版本.这是因为该版本中的许多工作都是基础设施,可以与为动态语言设计的对象模型实现更加无缝的互操作性.动态类型功能是显而易见的,但是还添加了许多其他小功能,它们结合在一起使得动态和遗留COM对象模型的使用变得更加容易.命名/可选参数只是其中之一.

事实上,我们现有的语言就像VB一样具有这种特定功能已有数十年而世界还没有结束,这进一步证明了该功能既可行又有价值.在设计新版本的功能之前,您可以从中获得成功和失败的例子.

至于你提到的具体情况:我们考虑做的事情就是检测何时可能存在歧义并发出警告,但这会打开另外一堆蠕虫.警告必须是常见的,合理的,几乎肯定是错误的代码,应该有一个明确的方法来解决导致警告消失的问题.编写模糊检测器是很多工作; 相信我,在重载分辨率中编写模糊度检测比编写代码来处理成功案例要花费更长的时间.我们不想花费大量时间为难以察觉的罕见情况添加警告,并且可能没有关于如何消除警告的明确建议.

另外,坦率地说,如果你编写的代码中你有两个方法,它们根据你调用的方法完全不同,那么你已经有了一个更大的设计问题!首先解决这个问题,而不是担心有人会不小心打错方法; 使它成为正确的方法之一.


Fru*_*erg 11

此行为由Microsoft在MSDN上指定.查看Named和Optional Arguments(C#编程指南).

如果判断两个候选者同样好,则优先选择没有可选参数的候选者,该参数在调用中被省略.这是对具有较少参数的候选者的重载分辨率的一般偏好的结果.

他们决定以这样的方式实现它的原因可能是,如果你想在之后重载一个方法.因此,您不必更改已编写的所有方法调用.

UPDATE

我很惊讶,Jon Skeet也没有真正的解释为什么他们这样做.