2008-12-14 46 views
28

我認爲這個問題的答案是如此明顯,以致沒有人對此寫過文章,但是遲到了,我真的無法解決這個問題。IoC容器的使用;特別是溫莎

我一直在閱讀IoC容器(在這種情況下是Windsor),我錯過了如何從代碼的各個部分與容器交談。

我得到DI,我一直在做可憐的人DI(空構造函數調用具有默認參數實現的重載注入構造函數)一段時間,我可以完全看到容器的好處。但是,我錯過了一條重要的信息;每當你需要服務時,你應該如何引用容器?

我是否創建了一個我傳遞的單個全局實例?當然不是!

我知道我應該把這個:

WindsorContainer container = new WindsorContainer(new XmlInterpreter()); 

(例如)時,我想我的加載XML配置,但後來我做什麼用的容器?每次創建一個新的容器後,通過一些內部靜態majicks或其他方式持久加載配置,或者每次都必須重新加載配置(我猜不是,或者生命週期不能工作)。

如果不明白這一點阻止我工作了生命週期是如何工作的,並獲得與使用一些國際奧委會awsomeness

感謝,

安德魯

回答

24

99%的情況下,它是每個應用的一個容器實例。通常你在Application_Start中初始化它(對於一個web應用程序),like this

之後,它真的取決於容器的消費者。例如,一些框架(如MonorailASP.NET MVC)允許您截取實例(本例中爲控制器)的創建,因此您只需在容器中註冊控制器及其依賴關係即可,只要您收到容器請求負責注入每個控制器及其依賴關係。例如參見this ASP.NET MVC controller。 在這些框架中,幾乎不需要調用甚至引用類中的容器,這是推薦的用法。

其他框架不會讓你在創建過程中很容易獲得(如Web表單),所以你不得不求助於黑客像this one,或所需要的依賴(即顯式調用容器)。要取消依賴關係,請使用靜態網關,如this onemaxnk所述的容器。請注意,通過這樣做,您實際上使用容器作爲服務定位器,它不會解耦和控制反轉。(請參閱區別herehere

希望這可以消除您的疑惑。

+0

實際上,如果你在尋找它,很多環境都會有一個「全局根」類。 Silverlight和WPF擁有App類(App.xaml的代碼隱藏),這與任何錨定IOC容器的地方都是一樣的。對於較大的WPF和Silverlight,你一定要看看Prism,它提供了大型結構化工具和Unity,這是MS的IOC容器。 – 2010-02-21 17:01:29

+0

@Cylon:和ASP.NET有Application_Start(),但這並不意味着它會讓你截取對象的創建。這隻意味着你有一個地方來設置容器。 – 2010-02-21 17:59:07

0

我使用的這一種實現接口:

public interface IResolver 
{ 
    object Resolve(Type type); 
    object Resolve(string name); 

    T Resolve<T>() where T : class; 
    T Resolve<T>(string name) where T : class; 
} 

這實際上是包裹在全球靜態類,例如:

public static class Resolver // : IResolver 
{ 
    private static IResolver _current; 

    public static object Resolve(Type type) 
    { 
     return Current.Resolve(type); 
    } 

    public static object Resolve(string name) 
    { 
     return Current.Resolve(name); 
    } 

    public static T Resolve<T>() where T : class 
    { 
     return Current.Resolve<T>(); 
    } 

    public static T Resolve<T>(string name) where T : class 
    { 
     return Current.Resolve<T>(name); 
    } 

    private static IResolver Current 
    { 
     get 
     { 
      if (_current == null) 
      { 
       _current = new SpringResolver(); 
      } 

      return _current; 
     } 
    } 
} 

而且我想遵循簡單的規則 - 使用解析器類儘可能少,而不是需要這些服務對象注入服務。

+4

-1用於推薦服務定位器。 – 2010-08-02 02:19:47

+0

但是(我意識到我遲到了這裏的遊戲),如果Resolver不是全局靜態類,而是將它作爲注入參數傳遞給需要創建自己對象的對象,那麼它將成爲抽象工廠,這比服務定位器更好,對嗎? – 2013-06-17 08:37:51

3

一般而言,您希望在整個應用程序的整個生命週期中只保留一個實例。 我大部分時間做的是我在應用程序啓動時初始化容器,然後使用輸入的工廠對容器不知情的對象拉動。

其他流行的方法是用靜態類包裝容器實例並使用該靜態類訪問您的(單例)容器。你可以在Ayende的Rhino.Commons庫here中找到一個例子。然而這種方法具有嚴重的缺點,應該避免。

1

正如另一個回答說,這裏有很多選擇,我們再次留給自己弄清楚在我們的情況下什麼是最好的。

那就是說,擁有一個在整個應用程序中訪問的全局容器的IMO有時會打破隔離,因爲現在很多代碼都依賴於一個全局類。此外,對於拆分爲多個程序集的應用程序,必須使所有這些程序集均可訪問全局容器。

隨着Unity你實際上可以在你的構造函數中有一個IUnityContainer參數,當你解決這個類時,容器會自動注入到實例中。這樣,對於需要解析您在容器中傳遞的其他服務的服務,而不是強制類引用外部類。

不確定其他框架如何支持這種情況(溫莎將注入IKernel)。