例如我有基类,我需要一个属性
将在派生类中计算。我有两个变体(SomeProperty1
和SomeProperty2
):
public class BaseClass
{
public int SomeProperty1{get;set;}
public override int SomeProperty2{get;set;}
}
public class DerivedClass : BaseClass
{
public DerivedClass()
{
SomeProperty1 = 100;
}
public override int SomeProperty2
{
get
{
return 100;
}
}
}
问题是最好的方法,SomeProperty1
或SomeProperty2
?
答案 0 :(得分:3)
向基类添加名为CalcSomeProperty()
的受保护抽象方法。
然后根据CalcSomeProperty()
实施您的媒体资源。这将迫使派生类实现它。
例如:
public abstract class BaseClass
{
public int SomeProperty
{
get
{
return CalcSomeProperty();
}
}
protected abstract int CalcSomeProperty();
}
或者,您可以将属性本身设为抽象:
public abstract class BaseClass
{
public abstract int SomeProperty { get; }
}
在任何一种情况下,都是强制派生类实现属性计算。
将计算分解为受保护方法(而不是使用更简单的抽象属性)的一个优点是,如果计算速度很慢,您可以在具体属性实现中执行缓存:
public abstract class BaseClass
{
protected BaseClass()
{
_someProperty = new Lazy<int>(CalcSomeProperty);
}
public int SomeProperty
{
get
{
return _someProperty.Value;
}
}
protected abstract int CalcSomeProperty();
private readonly Lazy<int> _someProperty;
}
答案 1 :(得分:0)
这很大程度上取决于计算的类型。如果它需要很长时间并且在对象的生命周期内没有变化,那么通过在属性中添加它会浪费计算时间。所以在这种情况下,我肯定会保持你的代码干净并在构造函数中初始化属性。
如果它是一个常量值,将它保留在构造函数中会更加清晰。您的构造函数反映了对象的外观。
显然,如果计算是动态的,你需要在属性中包含该部分。
注意:如果您有一个虚拟属性并在构造函数中初始化它,那么如果您的类不是sealed
,则会引入警告。 this thread比我更好地解释了这背后的“危险”。
答案 2 :(得分:0)
选项1主要用于用例,当属性应该初始化一次,初始化很容易而且很简单。
选项2允许控制初始化流程(例如,进行延迟初始化)。反过来,初始化流程取决于财产性质。
答案 3 :(得分:0)
如果您的意思是在子类中覆盖,那么您可能希望该属性为虚拟:
public virtual int SomeProperty2{get;set;}
虽然我最好在基类中声明一个公共属性,并且可以在子类中重写受保护的虚拟属性:
// base
protected virtual int SomePropertyInternal2
{
get
{
return 10;
}
}
public int SomeProperty2
{
get
{
return SomePropertyInternal2;
}
// child
protected override int SomePropertyInternal2
{
return 100;
}
在这种情况下,您将覆盖内部实施,而公共合同则保持不变。