我正在开发一个大量使用Singletons的遗留项目。虽然其中大部分都会更好地实施,但目前的目标是让它们受到考验。因此,我有以下结构。
public class SomeSingleton
{
private Dependency someDependency;
public static readonly SomeSingleton Instance = new SomeSingleton();
static SomeSingleton() {}
private SomeSingleton()
{
someDependency = new Dependency();
}
}
所以,为了让它在不失去'Singelton'的情况下可测试,我试图添加一个受保护的构造函数,它将依赖项作为参数调用来自我可以运行测试的继承类。我意识到将它打开继承也会打破Singleton模式,但它只是由测试框架使用,而不是按照惯例在生产代码中完成。
像这样:
public class SomeSingleton
{
private Dependency someDependency;
public static readonly SomeSingleton Instance = new SomeSingleton();
static SomeSingleton() {}
private SomeSingleton() : this(new Dependency()) {}
protected SomeSingleton(Dependency someDependency)
{
this.someDependency = someDependency;
}
}
public class SomeSingletonTestImplementation : SomeSingleton
{
public SomeSingletonTestImplementation (Dependency someDependency)
: base (someDependency) {}
}
最后,在设置之后,问题是:
通过这个实现,我期望从继承者中调用原始Singleton中的受保护构造函数。但是,当我调试时,调用继承器中的构造函数,但是,然后调用私有构造函数,而不是步进受保护的构造函数,然后调用受保护的构造函数。
有没有办法不调用私有构造函数?此外,如果有人简要解释为什么它会以它的方式发生,那就太好了。
谢谢!
答案 0 :(得分:4)
你的单例的静态只读实例就是调用no参数(私有)构造函数。
public static readonly SomeSingleton Instance = new SomeSingleton();
随后在测试用例中构建另一个实例
public SomeSingletonTestImplementation (Dependency someDependency)
: base (someDependency) {}
您可以安全地忽略正在创建的单例实例,测试中的实例将是您注入依赖项的实例。
答案 1 :(得分:1)
尝试注释掉单例实例的实例化;你可能正在看到私有构造函数被调用,因为你可以在第一次创建测试实现类的实例时调用你的单例类的静态初始化器(反过来初始化单例实例并调用私有构造函数。)
答案 2 :(得分:1)
正如Jamiec所解释的那样,由于初始化字段,首先调用私有构造函数。
在您进入受保护的构造函数之前将调用内联初始化,这就是为什么在调试私有ctor之前调用受保护的构造函数。
也许您可以简单地将Dependency字段(如果可能,使其成为属性)保护,以便您可以在初始化后更改它?
答案 3 :(得分:0)
感谢答案指出了我正确的方向。我得到的解决方案最终成为以下内容,无论如何,这对于典型的Singleton实现来说可能更为真实。
我没有使用公共变量,而是把它变成了一个懒惰地评估Singleton的静态属性。这样,私有构造函数仅在调用实际的Instance属性时调用,该属性从测试代码中永远不会发生,但始终来自生产代码。然后我可以通过受保护的构造函数插入模拟依赖项,并通过继承类测试所有公共方法。
public class SomeSingleton
{
private Dependency someDependency;
private static SomeSingleton instance;
public static SomeSingleton Instance
{
return instance ?? (instance = new SomeSingleton());
}
static SomeSingleton() {}
private SomeSingleton() : this(new Dependency()) {}
protected SomeSingleton(Dependency someDependency)
{
this.someDependency = someDependency;
}
}