简体   繁体   English

C# 可选参数:为什么我可以在接口和派生类上定义默认不同?

[英]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.作为脚注,我可以看到一些会导致问题的情况。

An interface changes the default value for one of its parameters接口更改其参数之一的默认值

This is already a binary-breaking change, and this would promote it to a source-breaking change.这已经是一个二进制破坏性更改,这将使其成为一个源破坏性更改。

Two interfaces with different default values具有不同默认值的两个接口

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.或者,您可以忽略这种情况,而不发出警告。

Adding an interface in a child class在子类中添加接口

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.

相关问题 为什么在接口上定义的 C# 4 可选参数没有在实现类上强制执行? - Why are C# 4 optional parameters defined on interface not enforced on implementing class? 当我在 class 派生形式的接口中调用它时,为什么需要将“this”强制转换为 C# 8.0 中具有默认实现的接口? - Why do I need to cast 'this' to an interface with a default implementation in C# 8.0 when I call it in the class derived form that interface? 在具有不同参数的接口中定义方法(C#) - Define a method in interface with different parameters (C#) 在C#中定义具有不同参数的接口方法 - define interface method with different parameters in C# 我可以在C#函数中为参数或可选参数赋予默认值吗? - Can I give a default value to parameters or optional parameters in C# functions? 在母版页(C#)中定义派生类 - Define derived class in Masterpage (c#) 实现定义基类属性的接口时,为什么类实现接口不能返回派生类类型对象? - When implementing an interface which define a base class property why can't the class implementing interface return a derived class type object? C#泛型接口实现到派生类 - C# generic Interface implementation to derived class 为什么我不能将一个隐式运算符从Base类写入C#中的Derived类? - Why can't I write an implicit operator from a Base class to a Derived class in C#? 在 C# 中用于验证父构造函数中参数的派生类中定义常量值的正确方法是什么 - What is the correct way to define a constant value in a derived class used to validate parameters in a parent constructor in C#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM