带有在构造函数中引用父属性的惰性单例

本文关键字:属性 单例 引用 构造函数 | 更新日期: 2023-09-27 18:07:57

我有一个作为web应用程序上下文对象的Singleton。这个Singleton遵循了Jon Skeets优秀的Lazy Singleton模型。

最终结果是一个Context.Current对象,作为许多函数的参考点。

我遇到的问题是这个对象的属性是一个叫做Providers的类。它为我提供了诸如ClientId之类的关于一系列云提供商的OAuth信息。

对于大多数提供商来说,ClientIds会根据端点而变化,所以在每个提供商的构造函数中,我检查…你猜对了,Context.Current.DeploymentType是一个ENUM,它告诉我我在哪个环境。

在对象的实例化过程中调用它是非常糟糕的形式,我最终使用:

ValueFactory attempted to access the Value property of this instance.

现在,我可以简单地不在Provider的构造函数中引用Context.Current.DeploymentType,而只是做ENUM在一次又一次实例化时所做的相同的工作,但感觉效率低下。

我可以单独创建ENUM,然后再创建Context.Current,但这感觉也不对。

我当前的代码是:

public Providers AllProviders = Providers.Instance;

有没有办法说:

public Providers AllProviders {get; don't instantiate me until someone calls me}

带有在构造函数中引用父属性的惰性单例

这实际上在单例模式中并不少见。被初始化的对象需要访问尚未初始化的单例的属性。通常,解决这个问题的方法是延迟初始化其他实例和属性来避免这个问题。

在您的示例中,由于其声明,该属性在对象构造期间被初始化。为了避免它在对象构造过程中被初始化,您可以这样做:

public Providers AllProviders
{
    get
    {
        if (this.allProviders == null) this.allProviders = Providers.Instance; // alternatively, do what Providers.Instance is actually doing
        return this.allProviders;
    }
}

看起来应该解决这个问题,如果我理解正确的话。通过进行此更改,在构造过程中不会初始化属性,并且提供程序。实例未被调用。它只在AllProviders被访问时被调用(然后缓存)。

当然,它不是线程安全的(除非提供程序。实例已经是线程安全的),你可能需要做一些工作来使它线程安全,这将发生与你所提出的方法(即。