我有一个抽象基类,我想声明一个字段或属性,在每个继承自此父类的类中具有不同的值.
我想在基类中定义它,所以我可以在基类方法中引用它 - 例如重写ToString来说"这个对象是属性/字段类型".我有三种方法可以看到这样做,但我想知道 - 这样做的最佳或可接受的方式是什么?新手问题,抱歉.
选项1:
使用抽象属性并在继承的类上覆盖它.这得益于强制执行(你必须覆盖它)并且它是干净的.但是,返回硬代码值而不是封装字段感觉有点不对,而且它只是几行代码而不仅仅是.我还必须为"集合"声明一个主体,但这不太重要(并且可能有一种方法可以避免我不知道的情况).
abstract class Father { abstract public int MyInt { get; set;} } class Son : Father { public override int MyInt { get { return 1; } set { } } }
选项2
我可以声明一个公共字段(或受保护的字段),并在继承的类中显式覆盖它.下面的例子会给我一个使用"new"的警告,我可能会这样做,但它感觉不对,它打破了多态性,这是重点.看起来不是一个好主意......
abstract class Mother { public int MyInt = 0; } class Daughter : Mother { public int MyInt = 1; }
选项3
我可以使用受保护的字段并在构造函数中设置值.这看起来很整洁,但依赖于我确保构造函数始终设置这个并且使用多个重载构造函数总是有可能某些代码路径不会设置该值.
abstract class Aunt { protected int MyInt; } class Niece : Aunt { public Niece() { MyInt = 1; } }
这是一个理论上的问题,我想答案必须是选项1,因为它是唯一安全的选择,但我只是想要掌握C#,并想问这个有更多经验的人.
在三种解决方案中,只有选项1是多态的.
字段本身不能被覆盖.这正是选项2返回 新关键字警告的原因.
警告的解决方案不是附加"new"关键字,而是实现选项1.
如果您需要将字段设置为多态,则需要将其包装在Property中.
如果您不需要多态行为,则选项3可以.您应该记住,在运行时访问属性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是非首发 - 您无法覆盖字段,您只能隐藏它们.
就个人而言,我每次都会选择选项1.我总是试着让田地保持私密.当然,如果你真的需要能够覆盖这个属性的话.另一个选项是在基类中具有一个只读属性,该属性是从构造函数参数设置的:
abstract class Mother { private readonly int 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".这可能会导致一些严重的可读性问题,以及后来的混乱.
就个人而言,我认为最好的选择是3; 因为它提供了一个清晰的集中值,并且可以由孩子在内部引用,而无需定义自己的字段 - 这是选项1的问题.
你可以这样做
class x { private int _myInt; public 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; } } }
virtual让您获得一个可以执行某些操作的主体的属性,并且仍然允许子类覆盖它。