У меня есть Singleton, который функционирует как объект контекста для веб-приложения. Этот Синглтон следует за Джоном Скетом отличной моделью Lazy Singleton.
Конечный результат, является Context.Current
объектом, который служит в качестве точки отсчета для многих функций.
Проблема, с которой я сталкиваюсь, - это свойство этого объекта, который называется классом Providers
. Это дает мне информацию OAuth, такую как ClientId, о серии поставщиков облачных вычислений.
ClientIds меняются в зависимости от конечной точки для большинства поставщиков, поэтому в конструкторе для каждого провайдера я проверяю... вы уже догадались, Context.Current.DeploymentType
который является ENUM
который сообщает мне, в какой среде я нахожусь.
Вызов объекта во время его создания - довольно плохая форма, и я получаю:
ValueFactory attempted to access the Value property of this instance.
Теперь я мог бы просто не ссылаться на Context.Current.DeploymentType
в конструкторе для Provider
и просто выполнять ту же работу, что и ENUM
, когда она создается снова и снова, но она неэффективна.
Я мог бы создать ENUM
отдельно, а затем снова для Context.Current
, но это тоже не так.
Мой текущий код:
public Providers AllProviders = Providers.Instance;
Есть ли способ сказать:
public Providers AllProviders {get; don't instantiate me until someone calls me}
На самом деле это не редкость в шаблоне Singleton. Инициализируемому объекту необходимо получить доступ к свойству из синглтона, который еще не инициализирован. Как правило, способ адресовать это - ленить инициализировать другие экземпляры и свойства, чтобы избежать этой проблемы.
В вашем примере свойство инициализируется при построении объекта из-за его объявления. Чтобы избежать его инициализации во время построения объекта, вы можете сделать это:
public Providers AllProviders
{
get
{
if (this.allProviders == null) this.allProviders = Providers.Instance; // alternatively, do what Providers.Instance is actually doing
return this.allProviders;
}
}
Похоже, это должно решить эту проблему, если я правильно ее понял. Сделав это изменение, во время строительства свойство не инициализируется, а Providers.Instance не вызывается. Он вызывается (а затем кэшируется) только при доступе к AllProviders.
Разумеется, он не является потокобезопасным (если Providers.Instance не является потокобезопасным), и вам, возможно, придется сделать некоторую работу, чтобы сделать его потокобезопасным, что произойдет с предложенным вами подходом (т.е. "не создавайте экземпляр, пока меня не назовут").