为DI容器创建线程安全的单例包装器
本文关键字:单例 包装 安全 创建 DI 线程 | 更新日期: 2023-09-27 18:18:41
我为Ninject DI容器创建了一个包装器,我打算在WPF应用程序中使用它。我希望它是线程安全的,以防我需要在分离的线程中打开新窗口,但我对使用易失性关键字和锁定感到困惑。就我所知,锁很容易理解,但我不喜欢使用volatile关键字。从我的谷歌搜索结果中,我了解到volatile关键字确保了多线程环境中指定实例的安全读访问,但在对指定实例占用的内存空间进行更改时不提供任何类型的安全。我将我的解决方案与一些线程安全的单例模式的例子结合起来,提出了这个包装器,它将作为我的服务定位器:
public class NinjectResolver
{
private static object syncRoot = new object();
private static volatile NinjectResolver instance = null;
private static volatile IKernel kernel = null;
public static NinjectResolver GetInstance()
{
lock (syncRoot)
{
if (instance == null)
instance = new NinjectResolver();
}
return instance;
}
static NinjectResolver()
{
lock (syncRoot)
{
if (kernel == null)
kernel = new StandardKernel();
}
}
public void AddBindings(Dictionary<Type, Type> bindings)
{
lock (syncRoot)
{
foreach (var binding in bindings)
{
Type IType = binding.Key;
Type ImplementationType = binding.Value;
kernel.Bind(IType).To(ImplementationType);
}
}
}
private NinjectResolver()
{
}
/// <summary>
/// Resolves All dependencies for requested instance and returns that instance
/// </summary>
/// <typeparam name="T">Requested Implementation type</typeparam>
/// <returns>Instance of Implementation type</returns>
public T Resolve<T>()
{
return kernel.TryGet<T>();
}
/// <summary>
/// Resolves property injection dependencies in already instantiated Implementation types
/// </summary>
/// <param name="obj">Specified instance of implementation type</param>
public void Inject(object obj)
{
kernel.Inject(obj);
}
}
我的问题是:我是否需要在指定的地方使用锁定,因为初始化将在App.xaml.cs (GetInstance()的第一次调用)内进行,并且这些静态字段需要声明为volatile,或者我可以省略这部分,因为它们在这个结构中或多或少是只读的。如果有人能解释一下,我会很感激的。
要实现一个线程安全的单例模式,你基本上有两个选择:
1。双重检查锁定
public static NinjectResolver GetInstance()
{
if(instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new NinjectResolver();
}
}
return instance;
}
2。在声明
时初始化实例private static volatile NinjectResolver instance = new NinjectResolver();
public static NinjectResolver GetInstance()
{
return instance;
}
也可以将代码放到静态块中,只使用:
private static volatile IKernel kernel = new StandardKernel();