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

时间:2011-12-24 13:50:52

标签: c# wpf multithreading .net-4.0 ninject

我为Ninject DI容器创建了一个包装器,我打算在WPF应用程序中使用它。我希望它是线程安全的,以防我需要在分离的线程中打开新窗口,但我对使用volatile关键字和锁定感到困惑。就我所知,锁定非常简单易懂,但我并不倾向于使用 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 个答案:

答案 0 :(得分:3)

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

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