4

例如,我有基类,我需要一个将在派生类中计算的属性。我有两个变体(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;
        }
    }
}

问题是什么是最好的方法,SomeProperty1或者SomeProperty2

4

4 回答 4

4

向基类添加一个受保护的抽象方法,称为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;
}
于 2013-04-01T09:50:34.000 回答
0

这在很大程度上取决于计算的类型。如果它需要很长时间并且在对象的生命周期内没有改变,那么通过将它添加到属性中会浪费计算时间。所以在那种情况下,我肯定会保持你的代码干净并在你的构造函数中初始化属性。

如果它是一个常量值,将它保存在构造函数中会更清楚。您的构造函数反映了您的对象的外观。

显然,如果计算是动态的,则您需要在属性中包含该部分。

注意:如果你有一个虚拟属性并且你在你的构造函数上初始化它,那么如果你的类不是,你会引入一个警告sealed。这背后的“危险”在这个线程中得到了比我更好的解释。

于 2013-04-01T09:51:54.407 回答
0

选项1主要用于用例,当属性应该初始化一次时,初始化很容易和微不足道。

选项 2 允许控制初始化流程(例如,进行延迟初始化)。反过来,初始化流程取决于属性性质。

于 2013-04-01T09:54:35.937 回答
0

如果您真的是要在子类中覆盖,那么也许您希望该属性是virtual

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

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

于 2013-04-01T09:57:26.863 回答