希望:使用默认参数通过另一个重载隐藏已弃用的方法

Wish: Hiding a Deprecated Method with Another Overload Using Default Parameters

请耐心等待,这不是(完全!)这些 SO 答案的副本:

当尝试 "influence" 编译器将选择什么重载给定由可选参数引起的冲突时,上述帖子中的答案引用了 C# Programming Guide,这表明重载解析 (OR) 启发式正在发挥作用这里:

If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call.

很公平。我的问题是,为什么 Obsolete 属性(或其他一些标记)不会(或为什么不能)影响 OR 判断两个候选人是否同样优秀的决定?例如,考虑以下重载:

[Obsolete(“This method is deprecated.”)]
[EditorBrowsable(EditorBrowsableState.Never)]]
bool foo() { return true; }

bool foo(bool optional = false) { return optional; }

似乎 OR 不应该判断这些重载同样好——带有可选参数的未弃用的重载应该获胜。如果在这个过度简化的示例中是这种情况,那么之前为 foo() 编译的代码将向后兼容并愉快地继续 return true。为该库编译的未来代码也可以调用 foo(),但已解决的重载将 return false。

这是我们语言中缺少的 valuable/possible 功能吗?或者有没有其他方法可以实现我的这个愿望?感谢您的任何见解,

-迈克

重载决议是一件非常棘手的事情,并且语言设计者对规则应该是什么进行了长期而艰苦的思考。您添加的不同考虑因素和特殊情况越多,语言用户可能会 运行 陷入晦涩难懂的陷阱,在这种情况下,它并不能完全按照他们期望的方式工作。我不认为将这个新条件添加到重载决策中会是对该语言的有价值的补充。

如果 OR 确实更喜欢没有 ObsoluteAttribute 的方法,那么在没有反射的情况下调用过时方法的唯一方法是这样的:

((Action)obj.foo)(); 

如果这是一个泛型方法,将无法使用匿名类型参数调用它。这绝对是令人惊讶的行为(至少对我而言)。

ObsoleteAttribute(用 IsError = false 声明)是一种为您的消费者提供提示以更新他们的代码而不完全删除以前的功能的方法。如果您计划在未来的版本中删除该功能,通常您会希望这样做。如果你想完全禁止他们调用这个方法,你可以:

  1. IsError = true 设置为 [Obsolete("This method is deprecated.", true)],这样如果重新编译代码,它会生成错误而不是警告。它仍然可以通过反射调用。
  2. 完全删除已弃用的功能。不能通过反射调用。

总而言之,有这样的代码...

[Obsolete(“This method is deprecated.”)]
bool foo() { return true; }

bool foo(bool optional = false) { return optional; }

臭臭的。当您调用 foo() 时,编译器会将算法应用于 select 正确的方法,但任何查看代码的开发人员都需要知道(并应用)该算法以了解代码的可维护性代码会减少很多。

在这种情况下,只需删除可选的,因为它比其他任何东西都更伤人。

这是个有趣的问题。尽管如此,出于以下原因,我还是更喜欢它:

简单

OR 取决于编译到模块的方法签名,这很直观。依赖任何属性都会将依赖范围更改为更宽 "thing" 并开始滚雪球 - 您是否应该考虑另一个属性?或参数的属性等..

变更管理

方法签名和 OR 与弃用标记属性不同。后者是元数据,如果它从某一点开始影响 OR,那么它可能会破坏许多现有应用程序。特别是出于某种原因弃用周期较长的库。

如果经过功能测试的代码在软决定代码的某一部分将在 "undetermined future" 中被淘汰后开始表现不同,我会非常恼火。