如何确保我的类Initialize方法只被调用一次,最好的方法是什么?

问题描述 投票:0回答:5

我目前正在使用 Unity IoC 容器,这是我的 AppConfig 类。正如你所看到的,Initialize 方法应该只被调用一次,我已经使用了双重锁检查来确保这一点。

如果我的方法不是最好的方法,那么实现这一目标的最佳方法是什么?

public interface IAppConfig
{
    /// <summary>
    /// Gets the admin username.
    /// </summary>
    /// <value>The admin username.</value>
    string AdminUsername { get; }

    /// <summary>
    /// Gets the admin password.
    /// </summary>
    /// <value>The admin password.</value>
    string AdminPassword { get; }

    /// <summary>
    /// Initializes this instance.
    /// </summary>
    void Initialize();
}

/// <summary>
/// A singleton App config which helps reading from web.config
/// its lifetime is controlled by Unity.
/// </summary>
public class AppConfig : IAppConfig
{
    #region Fields

    /// <summary>
    /// the injectable config manager
    /// </summary>
    private readonly IConfigManager _configManager;

    private readonly ILogger _logger;

    private static readonly object LockObject = new object();

    private static bool _initialized = false;

    #endregion

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="AppConfig"/> class.
    /// </summary>
    public AppConfig(IConfigManager configManager, ILogger logger)
    {
        this._configManager = configManager;
        this._logger = logger;
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets the admin username.
    /// </summary>
    /// <value>The admin username.</value>
    public string AdminUsername { get; private set; }

    /// <summary>
    /// Gets the admin password.
    /// </summary>
    /// <value>The admin password.</value>
    public string AdminPassword { get; private set; }

    #endregion

    #region Methods

    public void Initialize()
    {
        if (_initialized)
        {
            throw new ApplicationException("Initialize method should be called only once");
        }

        lock(LockObject)
        {
            if (_initialized) return;

            var adminUserNameSetting = _configManager.AppSettings[ConfigKeys.AdminUsername];

            if (adminUserNameSetting == null)
            {
                throw new ApplicationException("AdminUsername key not found");
            }

            this.AdminUsername = adminUserNameSetting.Value;

            if (String.IsNullOrWhiteSpace(this.AdminUsername))
            {
                _logger.LogError("AdminUsername not found");
            }

            // log
            var adminPasswordSetting = _configManager.AppSettings[ConfigKeys.AdminPassword];

            if (adminPasswordSetting == null)
            {
                throw new ApplicationException("AdminPassword key not found");
            }

            this.AdminPassword = adminPasswordSetting.Value;

            if (String.IsNullOrWhiteSpace(this.AdminPassword))
            {
                _logger.LogError("AdminPassword not found");
            }
            _initialized = true;
        }
    }

    #endregion
}

在Unity中,我使用以下代码:

// IAppConfig
container.RegisterType<IAppConfig, AppConfig>(new ContainerControlledLifetimeManager(),
                                              new InjectionConstructor(configManager,
                                                                       logger));
var appConfig = container.Resolve<IAppConfig>();
appConfig.Initialize();
c# asp.net design-patterns singleton unity-container
5个回答
3
投票

我认为

Initalize()
方法更像是一个实现问题。这意味着它可能根本不应该出现在界面中。

初始化实例最好留给构造函数。

如果您确实需要延迟初始化,那么您可以使用布尔值和锁来解决。


1
投票

根据您在 Initialize 方法中所做的判断,我认为您需要研究的是将该类注册为单例并持久化容器。您可以在此处查看执行此操作的示例:

http://gunnarpeipman.com/2008/04/unity-and-singletons/


0
投票

好吧,您依靠 Unity 来确保您的类是单例。虽然 C# 的代码模式非常简单。请参阅此处。然后在构造函数中调用初始化代码。

无论如何,我都会声明你的初始化标志是易失性的,因为代码处于atmo状态。


0
投票

我更喜欢有一个静态类实例变量来检查它是否已在 get 访问器中初始化。通过实例属性访问类,您将控制类初始化的次数。这几乎是默认的 C# 单例模式:

public static class MySingleton 
{
    private static Mutex instanceLock = new Mutex();

    private static MySingleton instance;
    public static MySingleton Instance
    {
        get
        {
            instanceLock.WaitOne();
            if(instance == null)
            {
                instance = new MySingleton();
            }
            instanceLock.ReleaseMutex();
            return instance;
         }
    }

    private MySingleton()
    {
        Initialize();
    }

    private void Initialize()
    {
        // Initialize
    }
}

public class MyOtherClass
{
    private MySingleton singleton = MySingleton.Instance;
}

0
投票

在类中创建一个内部/公共静态 bool 属性/var。再次初始化前进行验证。如果有人忽略了该步骤,在构造函数中,您可以验证属性/var 尚未设置,并抛出它已经创建的异常。

© www.soinside.com 2019 - 2024. All rights reserved.