2010-06-30 35 views
2

我正在爲自己的學習/成長寫一個IoC容器。通常我會寫一些像下面這樣:制定自定義IoC - 如何實施具有範圍的DI?

using(DisposableObject dispObj = new DisposableObject()) 
{ 
    UserRepository users = new UserRepository(dispObj); 

    // Do stuff with user. 
} 

將轉向:

using(IDisposableObject dispObj = Container.Resolve<IDisposableObject>()) 
{ 
    IUserRepository users = Container.Resolve<IUserRepository>(); 

    // Do stuff with user. 
} 

我怎麼能抽象的DisposableObject使其在using範圍內使用IOC時的唯一實例化的使用?我試圖弄清楚Autofac如何做,但我不完全確定。

編輯:當一個對象被與using範圍實例化,所有呼叫解決類型(在這種情況下IDisposableObject)應返回範圍的變量,而不是一個新的實例。同樣重要的是,在using聲明和另一個Resolve<IDisposableObject>被調用後,它會返回一個新的實例。

回答

2

以這種方式使用可丟棄對象時要記住的事情是容器中的引用也會被丟棄,所以最好在通過Resolve返回實例時它需要每次都返回一個新實例。

你需要做的,就是註冊時的類型與你的容器,允許它指定的行爲,無論是共享(單身),或者非共享,如:

Container.RegisterType<IDisposableObject>(CreationPolicy.NonShared); 

using (var disposable = Container.Resolve<IDisposableObject>()) { 

} 

以上將工作的非共享實例,因爲每次都創建一個新實例,所以我們可以安全地處理它。如果您使用CreationPolicy = Shared來嘗試上述操作,則Singleton將被丟棄,因此以後的訪問可能會導致ObjectDisposedException。

通過,你可以通過傳遞的creationPolicy =共享創建辛格爾頓情況下,建立這種行爲,例如:

Container.RegisterType<IUserRepository>(CreationPolicy.Shared); 

using (var disposable = Container.Resolve<IDisposableObject>()) { 
    var userRepository = Container.Resolve<IUserRepository>(); 
    // only one instance of user repository is created and persisted by the container. 
} 

希望幫助?

如果您以前使用過MEF,這個術語可能很熟悉。

編輯:所以,我的理解是,你想要做的事,如:

using (var repository = Container.Resolve<IUserRepository>()) 
{ 
    var other = Container.Resolve<IUserRepository>(); 
    // should resolve to the same instance. 
} 

你需要找到在容器監測一次性對象的某種方式。也許引進一個額外的創建策略,SharedScope,e.g:

Container.Register<IUserRepository, UserRepository>(CreationPolicy.SharedScope); 

現在,當您使用容器解決型,你需要弄清楚的項目把creationPolicy。如果項目是SharedScope,並且尚未創建,請創建它的一個實例並返回。

如果您解析實例並且它已經創建,則返回現有實例。

當在該項目上調用Dispose時,需要一些回調容器的方法來移除實例。

編輯兩個

那麼,有沒有搞清楚了這一點的一個簡單的方法。我能想到的唯一方法是你引入另一個接口:

public interface IMonitoredDisposable : IDisposable 
{ 
    bool IsDisposed { get; set; } 
} 

當一個對象被處置時,確保它設置了IsDisposed屬性。那麼您可以從您的容器中監控該財產嗎?

+0

那種答案我在找。我明白我需要通過某種「範圍」。我只想知道如何從我的字典中刪除單身人士,如果它已被丟棄?我想到的一種方式是使用(var localContainer = IoC.Create())'爲每個「範圍」創建一個新的容器,然後調用'localContainer.Resolve ()'在本地執行解析... – TheCloudlessSky 2010-06-30 18:29:23

+0

那麼,你不會處理單身人士,否則你將無法再返回他們。如果你的容器有一個Singletons的內部散列表,把它們存儲在那裏你可以很容易地抓住它們。如果要解析的類型未聲明爲Singleton,則只需通過Resolve <>將其返回而不存儲它。 使用具有Disposable模式問題的容器將不會是一個好的舉措,因爲您每次都必須設置和創建容器...... – 2010-06-30 19:05:02

+0

因此,如果您不處理Singleton,它們如何具體化到'使用'範圍?因爲它不被刪除,所以散列表中的關鍵字總是會碰到相同的單身人士(處置或不處理)。我認爲你錯過了如果在using語句中調用Container.Resolve ()*的問題,它應該引用從'using'範圍創建的問題。 – TheCloudlessSky 2010-06-30 21:05:55

2

您可以返回類型爲Owned<Foo>的對象而不是Foo

Owned<T>可能是這樣的:

public class Owned<T> : IDisposable 
{ 
    private readonly Container container; 
    private readonly T value; 

    public Owned(Container container, T value) 
    { 
     this.container = container; 
     this.value = value; 
    } 

    public T Value { get { return value; } } 

    public void Dispose() 
    { 
     this.container.ReleaseOwned(this); 
    } 

} 

現在客戶端拉Owned<Foo>可以通知通過佈置它這個對象的容器,即使Foo本身不是一次性的。通過這種方式,容器知道何時清理對象及其依賴關係(這可能也是一次性的,但對客戶端不可見),並且可以實現您之後的行爲。

Autofac做的事情非常相似。見Nicholas Blumhardt的博客文章The Relationship Zoo,他介紹了這個概念。

+0

昨天晚上我看到你的帖子之前,我最終找到了同樣的鏈接。唯一的問題是,沒有Resolve ()然後返回擁有而不是T?那麼,不是我的代碼總是必須依賴擁有的在'using'語句中,然後擁有。值得到實際的T? – TheCloudlessSky 2010-07-01 11:49:31

+0

調用代碼知道它是否需要所有權,所以它可以根據需要調用'Resolve >()'或'Resolve '。或者,如果您不喜歡基於請求類型的語義變化,您可以單獨使用'Resolve '和'ResolveOwned '方法。 – 2010-07-02 01:16:41

+0

好酷很有意義,如果我真的需要的東西,不能通知它已被處置。 – TheCloudlessSky 2010-07-02 12:49:34