覆盖子类中的字段或属性

我有一个抽象的基类,我想声明一个字段或属性,将从这个父类inheritance每个类中有不同的值。

我想在基类中定义它,所以我可以在基类方法中引用它 – 例如覆盖ToString来说“这个对象属性/字段types”。 我有三种方法可以看到这样做,但是我想知道 – 做这件事的最好方法是什么? 新手问题,对不起。

选项1:
使用抽象属性并在inheritance的类上覆盖它。 这受益于执行(你必须重写),它是干净的。 但是,返回一个硬编码值而不是封装一个字段感觉有点不对,它只是几行代码而不是简单的。 我还必须申报一个“设置”的机构,但这不重要(可能有办法避免我不知道的)。

abstract class Father { abstract public int MyInt { get; set;} } class Son : Father { public override int MyInt { get { return 1; } set { } } } 

选项2
我可以声明一个公共字段(或一个受保护的字段),并在inheritance的类中显式地覆盖它。 下面的例子会给我一个使用“新”的警告,我可以这样做,但是它感觉错了,它打破了多态,这是整个点。 似乎不是一个好主意…

 abstract class Mother { public int MyInt = 0; } class Daughter : Mother { public int MyInt = 1; } 

选项3
我可以使用受保护的字段,并在构造函数中设置值。 这似乎是相当整洁,但依靠我确保构造函数总是设置此和多个重载构造函数总是有一些机会代码path不会设置值。

 abstract class Aunt { protected int MyInt; } class Niece : Aunt { public Niece() { MyInt = 1; } } 

这是一个理论上的问题,我想答案必须是选项1,因为它是唯一的安全选项,但是我正在掌握C#,想要问这个有更多经验的人。

在这三种解决scheme中,只有选项1多态的

字段本身不能被覆盖。 这就是为什么选项2返回新的关键字警告。

警告的解决scheme不是追加“新”关键字,而是实现选项1。

如果你需要你的领域是多态的,你需要把它包装在一个Property中。

如果你不需要多态行为, 选项3是OK的。 您应该记住,在运行时访问属性MyInt时,派生类无法控制返回的值。 基类本身能够返回这个值。

这就是你的属性的一个真正的多态的实现可能看起来,允许派生类被控制

 abstract class Parent { abstract public int MyInt { get; } } class Father : Parent { public override int MyInt { get { /* Apply formula "X" and return a value */ } } } class Mother : Parent { public override int MyInt { get { /* Apply formula "Y" and return a value */ } } } 

选项2是一个非启动器 – 你不能覆盖字段,你只能隐藏它们。

就我个人而言,我会每次select1。 我试图在任何时候保持领域的私密性。 那当然,如果你真的需要能够覆盖这个属性的话。 另一种select是在基类中具有一个只读属性,该属性由构造函数参数设置:

 abstract class Mother { private readonly myInt; public int MyInt { get { return myInt; } } protected Mother(int myInt) { this.myInt = myInt; } } class Daughter : Mother { public Daughter() : base(1) { } } 

如果该值在实例的生命周期中不改变,那么这可能是最合适的方法。

选项2是一个坏主意。 这将导致所谓的阴影; 基本上你有两个不同的“MyInt”成员,一个在母亲身上,另一个在女儿身上。 问题在于,在母亲实施的方法将引用母亲的“MyInt”,而在女儿执行的方法将引用女儿的“MyInt”。 这可能会导致一些严重的可读性问题,以及后来的困惑。

我个人认为最好的select是3; 因为它提供了一个明确的集中价值,并且可以由儿童在内部引用而没有定义他们自己的领域的麻烦 – 这是选项1的问题。

你可以定义这样的东西:

 abstract class Father { //Do you need it public? protected readonly int MyInt; } class Son : Father { public Son() { MyInt = 1; } } 

通过将该值设置为只读,可以确保该类的值在对象的生命周期内保持不变。

我想下一个问题是:你为什么需要它?

你可以做到这一点

 class x { private int _myInt; internal virtual int myInt { get { return _myInt; } set { _myInt = value; } } } class y : x { private int _myYInt; public override int myInt { get { return _myYInt; } set { _myYInt = value; } } } 

虚拟让你得到一个属性,做一些事情,仍然让子类覆盖它的身体。

我会select3,但有一个抽象的setMyInt方法,子类被迫执行。 这样你就不会有忘记在构造函数中设置派生类的问题。

 abstract class Base { protected int myInt; protected abstract void setMyInt(); } class Derived : Base { override protected void setMyInt() { myInt = 3; } } 

顺便说一句,如果你不指定set, 在你的抽象基类的属性中,派生类不需要实现它。

 abstract class Father { abstract public int MyInt { get; } } class Son : Father { public override int MyInt { get { return 1; } } } 

如果修改抽象基类以在构造函数中要求属性值,则可以使用选项3,不会错过任何path。 我真的会考虑这个选项。

 abstract class Aunt { protected int MyInt; protected Aunt(int myInt) { MyInt = myInt; } } 

当然,你们仍然可以select私人领域,然后根据需要,公开一个受保护的或公共财产的获取者。

我做了这个…

 namespace Core.Text.Menus { public abstract class AbstractBaseClass { public string SELECT_MODEL; public string BROWSE_RECORDS; public string SETUP; } } namespace Core.Text.Menus { public class English : AbstractBaseClass { public English() { base.SELECT_MODEL = "Select Model"; base.BROWSE_RECORDS = "Browse Measurements"; base.SETUP = "Setup Instrument"; } } } 

这样你仍然可以使用字段。