【问题标题】:Change parameter name without breaking backwards compatibility在不破坏向后兼容性的情况下更改参数名称
【发布时间】:2016-10-29 17:12:57
【问题描述】:

我正在开发一个 c# 库,因此我们担心破坏向后兼容性,但我想知道是否可以仅更改参数的名称并保持向后兼容性,因为能够使用命名参数?下面是我正在尝试做的一个示例

[Obsolete("use ChangeSpecificFoo(SpecificFoo specificFoo)")]
public void ChangeSpecificFoo(SpecificFoo foo)
{
    _specificFoo = foo;
}

//Compile error ... already defines a member called 'ChangeSpecificFoo' with the same parameter types
public void ChangeSpecificFoo(SpecificFoo specificFoo)
{
    _specificFoo = specificFoo;
}

仅更改参数名称存在破坏向后兼容性的潜在风险,因为有人可能会使用诸如 ChangeSpecificFoo(foo: someSpecificFoo) 之类的命名参数调用该方法,但我们不能通过添加具有正确参数名称的新方法来弃用该方法,因为参数名称不包含在方法签名中,因此编译器将其视为重复。

有没有办法解决这个问题?我看到的唯一替代方法是更改​​方法名称,使其不重复,然后弃用旧方法,或者等到我们从参数列表中添加或删除参数并更改参数名称(这可能永远不会发生,因为方法是非常稳定),或者只是进行更改并修复我们在使用此库的代码中可能遇到的任何中断。

【问题讨论】:

  • 从功能上讲,这两种方法完全相同。将其中任何一个放在您的代码中都没有区别
  • @JonSkeet 我明白你在说什么,但现在我想知道为什么会这样?这似乎是一种愚蠢的做法......
  • @Andrew:在有多个相同类型的参数的情况下,可读性得到了巨大的改进......并且可选参数的有用性大大增加,如它允许指定任何可选参数。
  • 我将添加/更新 XML 注释块以澄清​​
  • @Andrew 人们为了更改名称而更改参数名称是一个非常小的问题。这在真实场景中确实不会发生,尤其是当您不拥有将调用您的方法的所有代码时。与往常一样,Jon Skeet 列举了很多(可能)极少数情况下您会选择使用命名参数的示例。

标签: c# backwards-compatibility named-parameters


【解决方案1】:

我对此的第一个倾向很简单:不要。您的参数名称在方法主体之外是无关紧要的。您认为人们通过名称来称呼它是正确的,因此可能会破坏它。但是,仅更改参数名称并没有真正的好处。

更改名称的唯一可能原因是重新定义方法的作用,因为旧名称会导致混淆。在这种情况下,方法的名称也应该更改,以免引起其他形式的混淆。 (方法签名相同的事实是不更改参数名称的第一个也是更重要的原因。但是,这可能会解释您可能想要的原因。)

但是,如果您仍然坚持保持相同的方法签名,但更改名称,您可以这样做。 (同样,我强烈建议您要么根本不要更改它,要么重命名方法以继续消除混淆。)

解决此问题的一种方法是让该方法具有两个参数,但将第二个参数设为可选。让最后一个参数使用旧名称,然后在方法中分配它。

我还强烈建议记录命名参数的任何使用情况,以查看您对人们将其称为命名参数的担忧是否有效。

public void ChangeSpecificFoo(SpecificFoo specificFoo = null, SpecificFoo foo = null)
{
    if (foo != null && specificFoo == null)
    {
        // Add any other details you can, especially 
        // to figure out who is calling this.
        Log("Someone used a name parameter!!");
    }
    _specificFoo = specificFoo ?? foo;
}

正如Dmitry Bychenko 在 cmets 中指出的那样,这不会阻止任何人像这样调用此方法:ChangeSpecificFoo(null, new SpecificFoo()),这将触发日志记录。

他的观察介绍了为什么这是一个坏主意的另一个原因:您现在引入了另一种方式,让人们“错误地”调用您的方法。因此,我将重复我在回答顶部的建议:不要这样做,除非您真的真的需要更改该参数名称。

【讨论】:

  • 从技术上讲,我可以在不使用命名参数的情况下调用ChangeSpecificFoo(null, new Foo());,并且此调用将被记录为命名为一个。
  • 是的,但是你也会记录下有人打电话给你,这是你不希望他们这样做的一种方式。我将编辑我的答案以包含该警告。不管你怎么做,这都是一个糟糕的主意。 但是,如果您有 0.0000001% 的边缘情况,而您真的需要这样做,这里有一个想法。
  • 澄清一下,我们希望更改参数名称的原因几乎完全是为了内部维护。显然这个例子过于简单化了,但是继续同样的例子,我们已经有一个名为 Foo 的对象,所以当它真的是一个 SpecificFoo 时,看到一个以 foo 的名字浮动的参数是令人困惑的。我们最终可能会做的是重命名方法顶部的参数,这样我们就不会感到困惑。如果混淆在于方法的命名,那么我们只需更改方法名称,但它已经有了我们想要的名称。
  • 是的。如果它与具有相同名称的成员变量造成混淆,那么重命名其他人看不到的变量就是要走的路。
猜你喜欢
  • 2019-08-29
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
  • 2023-04-02
  • 1970-01-01
  • 2011-03-11
  • 2012-08-12
  • 2013-04-18
相关资源
最近更新 更多