【发布时间】:2011-10-27 13:22:13
【问题描述】:
我目前正在使用 Unity IoC Container,这是我的 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();
【问题讨论】:
-
为什么不调用一次。这个超级顶级的防御性编程是怎么回事。
-
我会调用一次,但我想确保它被调用一次而不是错误调用两次!
-
对源代码进行静态分析是一个更好的解决方案,而不是使用锁定机制将源代码破解。
-
TL;DR,从构造函数调用它?
-
从构造函数调用它的问题是它变得不太可单元测试。
标签: c# asp.net design-patterns singleton unity-container