从具体子类中提取抽象类中的值的“正确”方法是什么?
即,我应该这样做:
abstract class A {
private string m_Value;
protected A(string value) {
m_Value = value;
}
public string Value {
get { return m_Value; }
}
}
class B : A {
B() : this("string value") {}
}
或者这个:
abstract class A {
protected A() { }
public abstract string Value { get; }
}
class B : A {
B() {}
public override string Value {
get { return "string value"; }
}
}
或其他什么?
如果Value
属性仅用于抽象类,那么应该做些不同的事情吗?
答案 0 :(得分:2)
我通常更喜欢第一种方法,因为它在子类中需要的代码更少。
但是,我承认第二种方法的语义以一种微妙的方式更加清晰。覆盖该属性说“此属性的实现是我的身份的一部分。”传递一个构造函数参数有一个不同的含义:“我正在设置另一个值,这恰好是我的基类。”它意味着组成(has-a)而不是继承(is-a)。
如果,应该做不同的事情 Value属性仅用于 抽象类?
在这种情况下,您绝对应该使用第一种(面向构造函数)方法,以便可以从子类中隐藏该实现细节。
同样,如果你需要在构造函数中使用该值;如Marc mentioned这是使用第一种方法的实际技术原因。虽然在这种特定情况下无关紧要,但如果某人稍后修改了属性覆盖以在派生类中使用某些其他成员变量,那么您可能会有一个微妙的错误。
答案 1 :(得分:1)
取决于;基类是否需要在ctor中了解它?如果是这样,override
方法可能是一个坏主意(virtual
在ctor内部不能很好地工作)。否则,两者都可以。
答案 2 :(得分:1)
我认为第二个成语更好,因为它更易于管理(如果您的基类需要在派生类中定义多个属性,构造函数可能会变得混乱)。信息的来源也更加清晰。如果您看到Value
属性,则您知道它是在子类中定义的。在第一个示例中,您必须跟踪m_Value
变量的定义点,该变量可以在基类中修改。
答案 3 :(得分:1)
我认为它几乎是一样的,选择一种方式并坚持一致性。
你的解决方案都强制派生类提供一个好的值;如果不需要值,可能的替代方案:
abstract class A {
public string Value {
get;
protected set;
}
}
我的个人偏好是你的第一个选择(构造函数参数),因为我个人认为它更清晰,但它确实是一个品味问题。
答案 4 :(得分:1)
取决于。
如果我需要在抽象类中修改Value
,我将使用第一种方式。
只有当我需要从A
继承许多类时才会使用第二种方法,我需要将继承的类封装到基本抽象类中。
如果以上两种情况都不属实,我会使用第二种更易于管理和清洁的方法。
如果Value
仅用于抽象类,我会将其声明为private
字段而不是属性。
答案 5 :(得分:0)
第二种情况的一个主要优点是它允许子类定义Value属性的行为,该行为可能比简单的标量值更复杂。例如,您可能希望根据子类定义的其他字段计算Value。使用第一种方法,这是不可能的,但第二种方法允许这样做。
答案 6 :(得分:0)
我更喜欢第二个。如果值是常量或可以在运行时计算,它允许您在不向类添加实际字段的情况下提供值。您拥有的状态越少(字段越少),您可能找到的代码就越容易维护。