通过抽象类构造函数中的虚拟成员分配只读字段

本文关键字:虚拟成员 分配 读字段 抽象类 构造函数 | 更新日期: 2023-09-27 18:32:32

我知道在SO上已经提出了类似的问题,但具体来说,我的问题涉及通过在抽象类的构造函数中调用虚拟成员来设置readonly字段的情况。

考虑以下抽象类:

public abstract class FooBase
{
    private readonly IDictionary<string,object> _readonlyCache;
    protected abstract IDictionary<string,object> SetCache();
    protected FooBase()
    {
        _readonlyCache = SetCache();
    }
}

问题:

1)这只是彻头彻尾的糟糕设计吗?

2)有更好的设计吗?

我知道您可以将FooBase的实现者声明为sealed,这将确保只调用SetCache()的正确实现。我不喜欢的是,没有办法强制实施者必须标记为sealed。非常欢迎任何建议。

通过抽象类构造函数中的虚拟成员分配只读字段

如果可能的话,这绝对是要避免的事情 - 在构造函数中调用虚拟方法总是有点臭,因为您将在子类执行初始化之前执行代码 - 它的构造函数主体不会执行。无论子类是否密封,都是如此;你处于一个根本上令人讨厌的境地。

您可能需要考虑让子类构造函数将缓存传递给构造函数:

public abstract class FooBase
{
    private readonly IDictionary<string,object> _readonlyCache;
    protected FooBase(IDictionary<string,object> cache)
    {
        _readonlyCache = cache;
    }
}

这样,直接子类就可以决定做什么 - 例如,它可能是抽象的,并从进一步派生的类中获取缓存,或者它可以构造自己的缓存。

1)是的,这是糟糕的设计,因为你不能强迫一个实现者被密封。 (我不明白你怎么能合理地把这种设计决策强加给别人的代码;控制别人的抽象级别不是由你来决定的。

2)是:例如,使ReadOnlyCache成为抽象或非抽象的属性,并在首次使用时调用抽象方法来获取其值:

private readonly IDictionary<string,object> _readonlyCache;
private IDictionary<string,object> ReadOnlyCache
{
    get
    {
        return _readonlyCache ?? _readonlyCache = GetEmptyCache();
    }
}
protected abstract IDictionary<string,object> GetEmptyCache();