关于何时调用受保护和私有构造函数的混淆

发布于 2024-11-02 08:32:37 字数 1221 浏览 0 评论 0原文

我正在开发一个大量使用单例的遗留项目。虽然其中大多数可以更好地实施,但目前的目标是让它们接受测试。因此,我有以下结构。

public class SomeSingleton
{
   private Dependency someDependency;
   public static readonly SomeSingleton Instance = new SomeSingleton();

   static SomeSingleton() {}

   private SomeSingleton()
   {
      someDependency = new Dependency();
   }
}

因此,为了使其可测试而不丢失“Singelton”特性,我尝试添加一个受保护的构造函数,该构造函数将依赖项作为参数,从我可以运行测试的继承类进行调用。我意识到,使其开放继承也破坏了单例模式,但它仅由测试框架使用,并且按照惯例,不在生产代码中完成。

就像这样:

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 中的受保护构造函数。但是,当我调试时,会调用继承者中的构造函数,但随后不会单步执行受保护的构造函数,而是调用私有构造函数,然后调用受保护的构造函数。

有什么办法可以让私有构造函数不被调用吗?另外,如果有人能简要解释为什么会这样,那就太好了。

谢谢!

I'm working on a legacy project that has heavy use of Singletons. While most of them would be better implemented otherwise, for now the goal is to get them under test. As such, I have the following structure.

public class SomeSingleton
{
   private Dependency someDependency;
   public static readonly SomeSingleton Instance = new SomeSingleton();

   static SomeSingleton() {}

   private SomeSingleton()
   {
      someDependency = new Dependency();
   }
}

So, to make it testable without losing the 'Singelton'ness', I've tried to add a protected constructor that takes the dependency as a parameter to call from an inheriting class that I can run tests through. I realize that making it open for inheritance is breaking the Singleton pattern as well, but it is only used by the test framework and not done, by convention, in the production code.

Like so:

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) {}
}

Finally, after the setup, the question:

With this implementation, I expected just the protected constructor in the original Singleton to be called from the inheritor. However, when I debug, the constructor in the inheritor is called, but then, instead of stepping into the protected constructor, the private constructor is called, and then the protected constructor.

Is there any way that the private constructor won't be called? Also, if anyone has a brief explanation of why it happens the way it does, that'd be great.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不…忘初心 2024-11-09 08:32:37

单例的静态只读实例是调用无参数(私有)构造函数的。

public static readonly SomeSingleton Instance = new SomeSingleton();

随后,您在测试用例中构造另一个实例,

public SomeSingletonTestImplementation (Dependency someDependency) 
      : base (someDependency) {}

您可以安全地忽略正在创建的单例实例,测试中的实例将是您注入依赖项的实例。

your static readonly instance of your singleton is what is calling the no parameter (private) constructor.

public static readonly SomeSingleton Instance = new SomeSingleton();

Subsequently you construct another instance in your test case

public SomeSingletonTestImplementation (Dependency someDependency) 
      : base (someDependency) {}

You can probably safely ignore the singleton instance being created, the one in your test will be the one where you've injected your dependancy.

瑾兮 2024-11-09 08:32:37

尝试注释掉单例实例的实例化;您可能会看到私有构造函数被调用,因为一旦您第一次创建测试实现类的实例,就可能会调用单例类的静态初始化程序(依次初始化单例实例并调用私有构造函数。)

Try commenting out the instantiation of the singleton instance; you may be seeing the private constructor being called because the static initializer of your singleton class may be called as soon as you first create an instance of the test implementation class (in turn initializing the singleton instance and calling the private constructor.)

陌伤ぢ 2024-11-09 08:32:37

正如 Jamiec 所解释的,正是因为初始化字段,私有构造函数才被首先调用。

内联初始化将在您进入受保护的构造函数之前被调用,这就是为什么当您调试时,私有构造函数会在受保护的构造函数之前被调用。

也许您可以简单地保护“依赖项”字段(如果可能,将其设置为属性),以便您可以在初始化后更改它?

As explained by Jamiec, it is because of the initialised field that the private constructor is called first.

The inline initialisation will be called before you step in the protected constructor, that's why when you debug the private ctor is called before the protected one.

Maybe you could simply make the Dependency field (make it a property if possible) protected so you can change it after initialization?

猥琐帝 2024-11-09 08:32:37

感谢为我指明正确方向的答案。我最终得出的解决方案如下,无论如何,这可能更适合典型的单例实现。

我没有使用公共变量,而是将其转换为延迟评估单例的静态属性。这样,只有在调用实际 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;
   }
}

Thanks to the answers that pointed me in the right direction. The solution that I came to ended up being the following, which is probably truer to a typical Singleton implementation anyway.

Instead of having a public variable, I turned it into a static property that lazily evaluates the Singleton. That way, the private constructor is only called when the actual Instance property is called, which never happens from the test code, but always from the production code. Then I can happily insert mock dependencies via the protected constructor and test all the public methods via the inheriting class.

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;
   }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文