我目前正在使用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();
答案 0 :(得分:3)
我认为Initalize()
方法更像是一个实现问题。这意味着它可能根本不应该在界面中。
初始化实例最好留给构造函数。
如果你确实需要一个延迟的Initialize,那么使用bool和一个锁的解决方案似乎没问题。
答案 1 :(得分:1)
根据您在Initialize方法中所做的事情判断,我认为您需要研究的是将该类注册为单例并持久化容器。你可以在这里看到这样做的一个例子:
答案 2 :(得分:0)
好的,所以你依靠Unity来确保你的班级是一个单身人士。虽然C#的代码模式非常简单。见here。然后在构造函数中调用初始化代码。
在任何情况下,我都会声明你的初始化标志是volatile,因为代码代表atmo。
答案 3 :(得分:0)
我更喜欢有一个静态类实例变量,用于检查它是否已在get访问器中初始化。通过instance属性访问该类,您将控制该类初始化的次数。这几乎是默认的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;
}