Путаница о том, когда защищенные и частные конструкторы называются - PullRequest
1 голос
/ 19 апреля 2011

Я работаю над унаследованным проектом, который интенсивно использует Singletons.Хотя большинство из них было бы лучше реализовано в противном случае, на данный момент цель состоит в том, чтобы проверить их.Таким образом, у меня есть следующая структура:

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

   static SomeSingleton() {}

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

Итак, чтобы сделать ее тестируемой без потери «Singelton'ness», я попытался добавить защищенный конструктор, который принимает зависимость в качестве параметра длявызов из наследующего класса, через который я могу выполнить тесты.Я понимаю, что открытие его для наследования также нарушает шаблон 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 будет вызван из наследника.Однако, когда я отлаживаю, вызывается конструктор в наследнике, но затем, вместо того, чтобы войти в защищенный конструктор, вызывается закрытый конструктор, а затем защищенный конструктор.

Есть ли способ, которым приватныйконструктор не будет называться?Кроме того, если у кого-то есть краткое объяснение того, почему так происходит, это было бы здорово.

Спасибо!

Ответы [ 4 ]

4 голосов
/ 19 апреля 2011

Ваш статический экземпляр только для чтения вашего синглтона - это то, что вызывает конструктор без параметров (приватный).

public static readonly SomeSingleton Instance = new SomeSingleton();

Впоследствии вы создаете другой экземпляр в своем тестовом примере.

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

Вероятно, вы можете спокойно игнорировать создаваемый экземпляр синглтона, тот, который в вашем тесте будет тем, где вы 'я ввел вашу зависимость.

1 голос
/ 19 апреля 2011

Как объяснил Jamiec, именно из-за инициализированного поля первый частный конструктор вызывается первым.

Встроенная инициализация будет вызываться до того, как вы перейдете в защищенный конструктор, поэтому при отладке вызывается частный ctor перед защищенным.

Может быть, вы могли бы просто сделать поле зависимостей (сделать его свойством, если возможно) защищенным, чтобы вы могли изменить его после инициализации?

1 голос
/ 19 апреля 2011

Попробуйте закомментировать экземпляр экземпляра singleton; вы можете видеть, что вызывается закрытый конструктор, потому что статический инициализатор вашего синглтон-класса может быть вызван, как только вы сначала создадите экземпляр класса реализации теста (в свою очередь, инициализируете экземпляр синглтона и вызовете закрытый конструктор.)

0 голосов
/ 19 апреля 2011

Благодаря ответам, которые указали мне правильное направление.В итоге я пришел к следующему решению, которое в любом случае, вероятно, более справедливо для типичной реализации 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;
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...