【问题标题】:In C#, why doesn't a subclass field's default value override the superclass field's default value? [duplicate]在 C# 中,为什么子类字段的默认值不覆盖超类字段的默认值? [复制]
【发布时间】:2021-03-01 05:43:08
【问题描述】:

我确定这是重复的,但我找不到答案。我是 C# 新手,无法理解为什么会发生这种情况:

我有一个类继承自另一个类。我希望子类覆盖超类上的公共字段,在本例中为公共字段a。但它似乎不起作用:

class Foo
{
   public string a = "x";

   public string A()
   {
      return a;
   }
}

class Bar : Foo
{
   public string a = "y";
}

...

new Foo().A() // Returns "x"
new Bar().A() // Returns "x" also...why?

我希望最后一行返回"y",但它返回"x",忽略了我已经覆盖a 字段的值这一事实。为什么它不起作用?获得我想要的行为的标准方法是什么?

我正在将此代码输入到csharp REPL,如果这很重要的话。

【问题讨论】:

  • 方法被覆盖,而不是字段。您可以为此行为使用虚拟方法。
  • 请注意编译器警告:'Bar.a' hides inherited member 'Foo.a'. Use the new keyword if hiding was intended。这暗示了这段代码有什么不好的地方,事实上,你并没有像你想象的那样覆盖该字段。

标签: c#


【解决方案1】:

您的代码隐藏了该字段,而不是覆盖它。

相当于这段代码:

class Bar : Foo
{
    public new string a = "y";
}

您的编译器应该在此代码上给您一个警告。

现在,由于您正在跟踪,这意味着在调用 A 时使用了 Foo 中的字段,就像 Bar 中的字段不存在一样。

您不能覆盖字段,但如果您将字段更改为属性,那么您可以这样做:

class Foo
{
    public virtual string a { get; set; } = "x";

    public string A()
    {
        return a;
    }
}

class Bar : Foo
{
    public override string a { get; set; } = "y";
}

现在您的代码会像您最初想象的那样运行:

void Main()
{
    Console.WriteLine(new Foo().A()); //x
    Console.WriteLine(new Bar().A()); //y
}

【讨论】:

    【解决方案2】:

    您必须用virtual 标记属性a 并在子类中覆盖它。

    在Foo:public virtual string a { get; set; } = "x";

    在酒吧:public override string a { get; set; } = "y";

    【讨论】:

    • 技术上还有new keyword,这可能更符合OP的预期。
    猜你喜欢
    • 2019-03-12
    • 2022-01-02
    • 1970-01-01
    • 2012-09-25
    • 1970-01-01
    • 2013-07-13
    • 2013-10-23
    • 2020-01-01
    • 2017-04-26
    相关资源
    最近更新 更多