I Created a wrapper for Ninject DI container which I intend to use in WPF application. I would like it to be thread safe in case I need to open new windows in separated threads, but I am confused about using volatile keyword and locking. As much as I'm aware of, locking is pretty much Straightforward to understand but I'm not shore about using volatile keyword. From my googling results I came to understanding that volatile keyword ensures safe read access for specified instance in multithreaded environment but doesn't provide any kind of safety when making changes in memory space occupied by the specified instance. I combined my solution with some examples of thread-safe singleton patterns and came up with this wrapper that would serve me as a service locator:
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);
}
}
My question is this: Do I need to use locking in specified places since initialization will take place inside App.xaml.cs (first call of GetInstance() ) and do these static fields need to be declared as volatile or I can omit that part since they are more or less readonly in this construction. I would appreciate if someone could shred some light on this.
To implement a thread-safe singleton pattern you have two options basically:
1.Double-checked locking
public static NinjectResolver GetInstance()
{
if(instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new NinjectResolver();
}
}
return instance;
}
2.Initialize the instance upon declaration
private static volatile NinjectResolver instance = new NinjectResolver();
public static NinjectResolver GetInstance()
{
return instance;
}
Also you can drop the code inside the static block and just use:
private static volatile IKernel kernel = new StandardKernel();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With