为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,或者我可以省略这部分,因为它们在这个结构中或多或少是只读的。如果有人能解释一下,我会很感激的。

为DI容器创建线程安全的单例包装器

要实现一个线程安全的单例模式,你基本上有两个选择:

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();