[英]C# optional parameters: Why can I define the default different on interface and derived class?
With C#, we now can have optional parameters , and give them default values like this:使用 C#,我们现在可以拥有可选参数,并为它们提供如下默认值:
public abstract class ImporterBase : IImporter {
public void ImportX(bool skipId = true) {
//....
}
}
Now, suppose in the interface we derive from, we have现在,假设在我们派生的接口中,我们有
public interface IImporter {
void ImportX(bool skipId = false);
}
See, that the default value is defined as different in the base class as in the interface.请看,默认值在基类中定义为与在接口中不同。 This is really confusing, as now the default value depends whether I do这真的很令人困惑,因为现在默认值取决于我是否这样做
IImporter interfaceImporter = new myConcreteImporter(); //which derives from ImporterBase
interfaceImporter.DoX(); //skipId = false
or或者
ImporterBase concreteImporter = new myConcreteImporter(); //which derives from ImporterBase
concreteImporter.DoX(); //skipId = true
Why is it allowed to define the default value differently in both the interface and the derived class?为什么允许在接口和派生类中定义不同的默认值?
Note: this question similar, but focuses on the optionality, not on the value.注意: 这个问题类似,但侧重于可选性,而不是价值。
There's a good reason for it.这是有充分理由的。 See here .见这里。
The short answer is though, if it treated the optional values as part of the method signature, it cause some problems.简短的回答是,如果它将可选值视为方法签名的一部分,则会导致一些问题。 Imagine the code below:想象一下下面的代码:
public abstract class A
{
public abstract void SomeFunction(bool flag);
}
public class B : A
{
public override void SomeFunction(bool flag = true)
{
//do something
Console.WriteLine(flag);
}
}
If the optional parameter value was part of the method signature then I'd get a compilation error since A doesn't have bool flag = true in the method signature.如果可选参数值是方法签名的一部分,那么我会收到编译错误,因为 A 在方法签名中没有 bool flag = true 。 It's an easy fix for sure but if you shipped A to a third party and their custom code created class B, they'd have to go change your code to have the optional parameter.这肯定是一个简单的修复,但是如果您将 A 发送给第三方并且他们的自定义代码创建了类 B,他们将不得不更改您的代码以具有可选参数。 Also keep in mind this is exacerbated when there are several levels of inheritance.还要记住,当存在多个继承级别时,这种情况会加剧。 So the easiest fix was to not consider the optional parameter value as part of the method signature for these purposes.因此,最简单的解决方法是不将可选参数值视为用于这些目的的方法签名的一部分。
To clarify, I'm interpreting the question to be:为了澄清,我将问题解释为:
If a method is defined in an interface / base class which has a method which has a parameter with a default value, and a class implements / overrides that method but provides a different default value, why doesn't the compiler warn?如果在接口/基类中定义了一个方法,该方法具有一个带有默认值的参数,并且一个类实现/覆盖了该方法但提供了不同的默认值,为什么编译器不发出警告?
Note that this doesn't cover the case where the implementation doesn't provide any default value -- that case is explained by Eric Lippert .请注意,这不包括实现不提供任何默认值的情况——这种情况由Eric Lippert解释。
I asked this on thecsharplang gitter channel , and the response from someone who has been heavily involved in the language design for a long time was:我在csharplang gitter 频道上问过这个问题,长期参与语言设计的人的回答是:
i think an analyzer sounds very good for this.我认为分析仪听起来非常适合这个。
From that, and the other links posted here (which don't even mention this specific case), my best guess is that this specific case just wasn't considered, or was briefly considered but dismissed as too niche.从那个,以及这里发布的其他链接(甚至没有提到这个特定案例),我最好的猜测是这个特定案例没有被考虑,或者被简单考虑但被认为太小众而被驳回。 Of course, once C# 4 was released, there was no way to add a compiler error or warning without breaking backwards compatibility.当然,一旦 C# 4 发布,就无法在不破坏向后兼容性的情况下添加编译器错误或警告。
You could write an analyzer which catches this case (which had a code fix to correct the default value), and try to get it incorporated into Roslyn.你可以编写一个分析器来捕捉这种情况(它有一个代码修复来纠正默认值),并尝试将它合并到 Roslyn 中。
As a footnote, there are a few cases I can see which would cause issues.作为脚注,我可以看到一些会导致问题的情况。
This is already a binary-breaking change, and this would promote it to a source-breaking change.这已经是一个二进制破坏性更改,这将使其成为一个源破坏性更改。
interface I1
{
void Foo(bool x = false);
}
interface I2
{
void Foo(bool x = true);
}
class C : I1, I2
{
...?
}
If you did want to specify a default value for C.Foo
, this case could be solved by explicitly implementing one of the interfaces:如果您确实想为C.Foo
指定默认值, C.Foo
可以通过显式实现以下接口之一来解决这种情况:
class C : I1, I2
{
public void Foo(bool x = false) { ... }
void I2.Foo(bool x) => Foo(x);
}
Alternatively you could just ignore this case, and not warn.或者,您可以忽略这种情况,而不发出警告。
interface I1
{
void Foo(bool x = false);
}
class Parent
{
public void Foo(bool x = true) { ... }
}
class Child : Parent, I1
{
...?
}
I'm not sure what an intuitive solution to this would be, but since it's so niche I'd be tempted just to ignore it, and not warn.我不确定对此的直观解决方案是什么,但由于它是如此小众,我很想忽略它,而不是警告。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.