我知道在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
。任何建议都非常受欢迎。
答案 0 :(得分:4)
如果可能的话,肯定要避免这种情况 - 在构造函数中调用虚方法总是有点臭,因为在子类执行初始化之前你将执行代码 - 它的构造函数体不会被执行。无论子类是否密封,都是如此;你处于一个根本恶劣的境地。
您可能需要考虑使子类构造函数将缓存传递给构造函数:
public abstract class FooBase
{
private readonly IDictionary<string,object> _readonlyCache;
protected FooBase(IDictionary<string,object> cache)
{
_readonlyCache = cache;
}
}
这样 direct 子类就可以决定做什么 - 例如,它可能是抽象的,并从进一步派生的类中获取缓存,或者它可能构造自己的。
答案 1 :(得分:1)
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();