覆盖属性或计算构造函数中的属性

时间:2013-04-01 09:44:03

标签: c# .net inheritance polymorphism virtual

例如我有基类,我需要一个属性 将在派生类中计算。我有两个变体(SomeProperty1SomeProperty2):

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;
        }
    }
}

问题是最好的方法,SomeProperty1SomeProperty2

4 个答案:

答案 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;
}

在这种情况下,您将覆盖内部实施,而公共合同则保持不变。