为啥 C# 可以重载具有相同参数的两个方法,只要其中一个具有默认参数?
Posted
技术标签:
【中文标题】为啥 C# 可以重载具有相同参数的两个方法,只要其中一个具有默认参数?【英文标题】:Why could C# overload two methods with the same params as long as one of them has default param?为什么 C# 可以重载具有相同参数的两个方法,只要其中一个具有默认参数? 【发布时间】:2021-11-09 06:53:07 【问题描述】:我最近注意到 C# 编译器允许方法重载,如下所示:
public static string foo(string a, bool x = false)
return "a";
public static string foo(string a)
return "b";
据我测试,只要没有给出第二个参数,它总是返回“b”,这是有道理的。但是,我认为编译器确实不应该允许这种类型的重载。请问为什么这个功能是这样设计的,而不是编译器报错?
【问题讨论】:
那么这个问题还是陈述?这实际上是 C# ECMA 规范中称为重载解析的一个非常深入的主题,它可以在编译或运行时发生。说某事应该以不同的方式工作是可以的(也许你已经以各种可以想象的方式完全考虑了这一点,所以他们应该聘请你加入 Roslyn 和运行时团队),但是我们无能为力However, I think the compiler really should not allow this type of overloading.
你为什么这么认为?
Why could C# overload two methods with the same params as long as one of them has default param?
显而易见的答案是它们没有具有相同的参数。
你可能会看到这种警告:Method with optional parameter is hidden by overload.
顺便说一句,我发现微软确实在他们的文档中声明了重载解决方案:docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…
【参考方案1】:
虽然这样的问题根本无法回答,但由于无法猜测语言设计者的意图,我可能会猜测一下。
通过转换代码以将参数注入调用站点来处理可选参数。所以
public static void Test(int a = 42)...
...
Test();
将被转换为
public static void Test(int a)...
...
Test(42);
由编译器。从这一点开始,常规重载解决方案可以运行而不会发生冲突。为什么要这样设计?我不知道,但非直观功能的常见原因是向后兼容性或语言兼容性。
因此,在公共 API 中使用可选参数时要非常小心,这一点很重要。由于库的用户将使用编译它的 API 版本中的默认值。不是它运行的版本。
【讨论】:
【参考方案2】:我无法解释为什么这是设计的一部分,只是简单地解释为什么您会看到在您的测试中偏爱哪种重载。
如果您查看reference documentation,您会注意到以下三个项目符号来描述重载解决方案:
如果方法、索引器或构造函数的每个参数都是可选的,或者按名称或位置对应于调用语句中的单个参数,并且该参数可以转换为类型参数。 如果找到多个候选者,则会将首选转换的重载决策规则应用于明确指定的参数。忽略可选参数的省略参数。 如果两个候选者被判定为同样优秀,则优先选择没有可选参数的候选者,而该候选者的参数在调用中被省略。重载解析通常更喜欢参数较少的候选。我会断言,在您的测试中,第 3 条最适用于您的观察 - 因为您省略了第二个参数并且任何一种方法都同样好,分辨率有利于您的第二种方法,并且您会看到“b”返回。
【讨论】:
以上是关于为啥 C# 可以重载具有相同参数的两个方法,只要其中一个具有默认参数?的主要内容,如果未能解决你的问题,请参考以下文章