Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/google-app-engine/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在不破坏向后兼容性的情况下更改参数名称_C#_Backwards Compatibility_Named Parameters - Fatal编程技术网

C# 在不破坏向后兼容性的情况下更改参数名称

C# 在不破坏向后兼容性的情况下更改参数名称,c#,backwards-compatibility,named-parameters,C#,Backwards Compatibility,Named Parameters,我正在开发一个c#库,因此我们担心破坏向后兼容性,但我想知道是否有可能仅仅更改参数的名称,并因为能够使用命名参数而保持向后兼容性?下面是我试图做的一个例子 [Obsolete("use ChangeSpecificFoo(SpecificFoo specificFoo)")] public void ChangeSpecificFoo(SpecificFoo foo) { _specificFoo = foo; } //Compile error ... already defines

我正在开发一个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)
,但是我们不能通过添加具有正确参数名的新方法来反对该方法,因为参数名不包含在方法签名中,因此编译器将其视为重复


这有什么办法吗?我看到的唯一替代方法是更改方法名称,使其不再重复,然后弃用旧方法,或者等到我们从参数列表中添加或删除参数,然后更改参数名称(这可能永远不会发生,因为该方法非常稳定),或者,在我们找到代码库时,对代码进行更改并修复可能出现的任何中断。

我对此的第一个倾向很简单:不要。参数的名称在方法体之外是无关的。你应该考虑人们以名字来称呼它,因此可能会打破它。然而,仅仅更改参数的名称并没有带来真正的好处

更改名称的唯一可能原因是重新定义方法的功能,因为旧名称会导致混淆。在这种情况下,还应更改方法的名称,以避免引入另一种形式的混淆。(方法签名相同这一事实是不更改参数名称的第一个也是更重要的原因。不过,这可能是为了解释为什么您可能希望更改参数名称。)

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

解决这个问题的一种方法是使方法同时具有两个参数,但使第二个参数成为可选的。让最后一个参数使用旧名称,然后在方法中指定它

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

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;
}
正如评论中所指出的,这不会阻止任何人像这样调用此方法:
ChangeSpecificFoo(null,newspecificfoo())
,这将触发日志记录


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

从功能上讲,这两种方法完全相同。将它们中的任何一个放在代码中都不会产生任何效果difference@JonSkeet我明白你的意思,但现在我想知道为什么会这样?这似乎是一种愚蠢的方式…@Andrew:在不同的情况下,有多个相同类型的参数,可读性有了巨大的提高。。。可选参数的实用性大大增加,因为它允许指定任何可选参数clarify@Andrew人们为了更改名称而更改参数的名称是一个非常次要的问题。在真实场景中,这种情况永远不会发生,尤其是当您不拥有将调用您的方法的所有代码时。和往常一样,Jon Skeet列举了很多(可能)罕见的例子,当您选择使用命名参数时不使用命名参数,此调用将以命名的方式记录。是的,但是您也将记录有人正在调用,这是您不希望他们使用的方式。我将编辑我的答案以包含该警告。不管你怎么做,这都是个糟糕的主意。但是,如果你有0.0000001%的边缘情况下,你真的需要这样做,这里有一个想法。为了澄清,我们正在寻找改变参数名称的原因几乎完全是为了内部维护。显然,这个例子过于简单化了,但为了继续这个例子,我们已经有了一个名为Foo的对象,因此看到一个名为Foo的参数四处浮动时,当它实际上是一个特定的Foo时,会让人感到困惑。我们最终可能要做的是重命名方法顶部的参数,这样我们就不会有这种混乱。如果混淆是在方法的命名上,那么我们只需要更改方法名称,但它已经有了我们想要的名称。是的。如果它导致与同名的成员变量混淆,那么重命名其他人看不到的成员变量是一种方法。