2011-12-24 75 views
3

我爲Ninject DI容器創建了一個打包器,我打算在WPF應用程序中使用它。我希望它是線程安全的,以防我需要在分開的線程中打開新窗口,但我對使用volatile關鍵字和鎖定感到困惑。儘管我知道,鎖定非常直截了當,但我並不支持使用易失性關鍵字。從我的搜索結果中,我瞭解到volatile關鍵字可確保多線程環境中指定實例的安全讀取訪問,但在指定實例佔用的內存空間發生更改時不提供任何安全措施。我用的是線程安全的單模式的一些例子結合我的解決方案,並與該包裝,將成爲我作爲一個服務定位器上來:爲DI容器創建線程安全的單例包裝器

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()),並且這些靜態字段需要聲明爲易失性或者我可以省略該部分,因爲它們在此處或多或少是隻讀的施工。如果有人能夠對此有所瞭解,我將不勝感激。

+1

由於您已知的原因,您可以省略volatile。鎖定是好的。另外,當我讀到「有人可以撕掉一些光」時,我咯咯地笑着,想着如果只有查克·諾里斯能讀到這個:) –

+0

那麼,我們都有我們的「特殊時刻」......謝謝你的回答。 – Stanque

回答

3

要實現線程安全的Singleton模式,你有兩種基本選擇:

。雙檢查鎖定

public static NinjectResolver GetInstance() 
{ 
    if(instance == null) 
    { 
     lock (syncRoot) 
     { 
      if (instance == null) 
       instance = new NinjectResolver(); 
     } 
    } 
    return instance; 
} 

2.Initialize在聲明實例

private static volatile NinjectResolver instance = new NinjectResolver(); 

public static NinjectResolver GetInstance() 
{ 
    return instance; 
} 

而且您可以將代碼放在靜態塊內,然後使用:

private static volatile IKernel kernel = new StandardKernel(); 
+0

我不明白你的答案是否需要同時使用volatile關鍵字和鎖定?第二種方法在我的情況下會很好,但我認爲這會在應用程序生命週期中可選地需要昂貴實例的情況下開銷。感謝您指示我在鎖定時仔細檢查實例,我忘了這一點。 – Stanque

+0

@Stanque:如果你要用鎖進行懶惰初始化,那麼不需要volatile,因爲鎖引入了隱式內存限制。 – Tudor

+0

感謝您澄清。 – Stanque