为什么不能像在方法上那样对类变量使用虚/覆盖? [英] Why can't I use virtual/override on class variables as I can on methods?

查看:77
本文介绍了为什么不能像在方法上那样对类变量使用虚/覆盖?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的示例中,我可以在继承的类中创建虚拟方法Show(),然后在<继承类.

In the following example I am able to create a virtual method Show() in the inherited class and then override it in the inheriting class.

我想使用受保护的类变量 prefix进行相同的操作,但出现错误:

I want to do the same thing with the protected class variable prefix but I get the error:

修饰语虚拟"无效 为此项目

The modifier 'virtual' is not valid for this item

但是由于我无法在类中将此变量定义为 virtual/override ,因此我得到了编译器警告:

But since I can't define this variable as virtual/override in my classes, I get the compiler warning:

TestOverride234355.SecondaryTransaction.prefix' 隐藏继承的成员 'TestOverride234355.Transaction.prefix'. 如果隐藏是

TestOverride234355.SecondaryTransaction.prefix' hides inherited member 'TestOverride234355.Transaction.prefix'. Use the new keyword if hiding was intended.

幸运的是,当我添加new关键字时,所有内容都可以正常运行,这没关系,因为我获得了相同的功能,但这引发了两个问题:

Luckily when I add the new keyword everything works fine, which is ok since I get the same functionality, but this raises two questions:

  1. 为什么我可以对方法使用虚拟/覆盖,但不能对受保护的类变量使用虚拟/覆盖?

虚拟/覆盖方法和新隐藏"方法之间的实际区别是什么?至少在此示例中,它们提供了相同的功能?

代码:

using System;

namespace TestOverride234355
{
    public class Program
    {
        static void Main(string[] args)
        {
            Transaction st1 = new Transaction { Name = "name1", State = "state1" };
            SecondaryTransaction st2 = 
                new SecondaryTransaction { Name = "name1", State = "state1" };

            Console.WriteLine(st1.Show());
            Console.WriteLine(st2.Show());

            Console.ReadLine();
        }
    }

    public class Transaction
    {
        public string Name { get; set; }
        public string State { get; set; }

        protected string prefix = "Primary";

        public virtual string Show()
        {
            return String.Format("{0}: {1}, {2}", prefix, Name, State);
        }
    }

    public class SecondaryTransaction : Transaction
    {
        protected new string prefix = "Secondary";

        public override string Show()
        {
            return String.Format("{0}: {1}, {2}", prefix, Name, State);
        }
    }
}

推荐答案

覆盖字段实际上没有任何意义.它是基类状态的一部分,如果继承类希望对其进行更改,则应该在继承类中通过赋予其适当的可见性来对其进行更改.

Overriding a field does not really make sense. It's part of the state of the base class, and if an inheriting class wishes to change it, it should be changable in the inheriting class by giving it an appropriate visibility.

您可以做的一件事是在继承类的构造函数中设置prefix:

One thing you could do in your case is to set prefix in the constructor for the inheriting class:

// Base class field declaration and constructor
protected string prefix;

public Transaction()
{
  prefix = "Primary";
}

// Child class constructor
public SecondaryTransaction()
{
  prefix = "Secondary";
}

您还可以使属性(而不是字段)成为虚拟属性.这将使您能够更改继承类中属性的getter和setter的行为:

You can also make a property instead of a field, and make the property virtual. This will enable you to change the behavior of the getter and setter for the property in the inheriting class:

// Base class
public virtual string Prefix { get { /* ... */ } set { /* ... */ } }

// Child class
public override string Prefix { get { /* ... */ } set { /* ... */ } }

关于在继承类设置变量之前在基本构造函数中使用变量的问题,解决此问题的一种方法是在基类中定义一个初始化方法,并覆盖它在继承的类中,并在访问任何字段之前从基本构造函数调用它:

As for your question of using a variable in a base constructor before an inheriting class has set it, one way to solve this is to define an initialization method in the base class, override it in the inheriting class, and call it from the base constructor before accessing any fields:

// Base class
public class Base
{
  protected string prefix;

  public Base()
  {
    Initialize();
    Console.WriteLine(prefix);
  }  

  protected virtual void Initialize()
  {
    prefix = "Primary";
  }
}

// Inheriting class
public class Child : Base
{
  public override void Initialize()
  {
    prefix = "Secondary";
  }
}

您还询问了虚拟/覆盖和名称隐藏(方法上的新关键字)之间的区别,是否应该避免以及是否有用.

EDIT 2: You also asked what the difference between virtual/override and name hiding (the new keyword on methods) is, if it should be avoided, and if it can be useful.

名称隐藏是一种在隐藏虚拟方法的情况下中断继承的功能.即,如果您在子类中隐藏Initialize()方法,则基类将不会看到它,也不会调用它.另外,如果Initialize()方法是公共的,则在基本类型的引用上调用Initialize()的外部代码将在基本类型上调用Initialize().

Name hiding is a feature that breaks inheritance in the case of hiding virtual methods. I.e., if you hide the Initialize() method in the child class, the base class will not see it, and not call it. Also, if the Initialize() method was public, external code that was calling Initialize() on a reference of the base type would be calling Initialize() on the base type.

名称隐藏非常有用.但是请注意,这 NOT 与虚拟/替代相同.基本类型的引用将调用基本类型实现,子类型的引用将调用子类型实现.

Name hiding is useful when a method is non-virtual in a base class, and a child wants to provide a different implementation of its own. Note, however, that this is NOT the same as virtual/override. References of the base type will call the base type implementation, and references of the child type will call the child type implementation.

这篇关于为什么不能像在方法上那样对类变量使用虚/覆盖?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆