Как убедиться, что мой метод Initialize класса вызывается только один раз, что будет лучшим подходом? - PullRequest
0 голосов
/ 27 октября 2011

В настоящее время я использую контейнер 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();

Ответы [ 4 ]

3 голосов
/ 27 октября 2011

Я думаю, что метод Initalize() больше похож на проблему реализации.А это значит, что, возможно, его вообще не должно быть в интерфейсе.

Инициализация экземпляра лучше оставить конструктору.

Если вам действительно нужна отложенная инициализация, тогда вы решаете с помощью bool, и блокировка выглядит нормально.

1 голос
/ 27 октября 2011

Судя по тому, что вы делаете в методе Initialize, я думаю, что вам нужно обратить внимание на регистрацию этого класса в качестве одиночного и сохранение контейнера.Вы можете увидеть пример этого здесь:

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

0 голосов
/ 27 октября 2011

Я предпочитаю иметь переменную экземпляра статического класса, которая проверяет, была ли она инициализирована в методе доступа get. Получите доступ к классу через свойство экземпляра, и вы будете контролировать, сколько раз класс инициализируется. Это в значительной степени стандартный шаблон C # singleton:

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 голосов
/ 27 октября 2011

Хорошо, так что вы полагаетесь на Unity, чтобы гарантировать, что ваш класс является единственным.Хотя шаблон кода для C # довольно прост.Смотрите здесь .Затем вызовите код инициализации в конструкторе.

В любом случае я бы объявил ваш флаг инициализации энергозависимым, поскольку код находится в режиме atmo.

...