2012-09-05 65 views
15

我有一個Ninject被用作IoC容器的項目。我擔心的是,很多班級有這樣那樣的構造函數:懶惰依賴注入

[Inject] 
public HomeController(
    UserManager userManager, RoleManager roleManager, BlahblahManager blahblahManager) { 
    _userManager = userManager; 
    _roleManager = roleManager; 
    _blahblahManager = blahblahManager; 
} 

如果我不希望有這些類的所有實例一次?

所有這些類都被Lazy<T>包裝並傳遞給構造函數的方式並不完全是我所需要的。 T實例尚未創建,但Lazy<T>實例已存儲在內存中。

我的同事建議我使用Factory模式來控制所有的實例,但我不確定IoC是否有如此出色的設計錯誤。

對於這種情況有沒有解決方法,或者IoC在設計中真的有這麼大的缺陷嗎?也許我應該使用另一個IoC容器?

有什麼建議嗎?

+0

實際上你的問題是什麼?你爲什麼不想要這些實例? –

+2

在控制器工作期間,我可能需要UserManager,但不需要RoleManager,反之亦然。如果你談論懶惰實例,那麼讓它們在內存中並不是一件大事,但這是唯一的方法嗎? – xwrs

+1

爲什麼'UserManager'和'RoleManager'很重要?無論如何,你的施工人員不應該做繁重的工作。 –

回答

36

對我來說,你在做premature optimization:不這樣做。

您的服務的構造函數應該執行nothing more而不是存儲它在私有字段中所需的依賴項。在這種情況下,創建這樣的對象真的很輕。不要忘記,.NET中的對象創建非常快。在大多數情況下,從性能角度來看,這些依賴關係是否被注入並不重要。特別是當與應用程序的剩餘部分(以及您使用的框架)正在吐出的對象數量相比較時。真正的成本是當您開始使用Web服務,數據庫或文件系統(或一般的I/O)時,因爲它們會導致更大的延遲。

如果創作真的很貴,你通常應該隱藏Virtual Proxy背後的創作,而不是注射在每一位消費者Lazy<T>的,因爲這可以讓普通的應用程序代碼留無視這樣的事實,有推遲建立一個機制(當你這樣做時,你的應用程序代碼和測試代碼都變得越來越複雜)。

Dependency Injection in .NET, second edition的第6章包含關於懶惰和虛擬代理的更詳細的討論。

然而,Lazy<T>只是消耗20個字節的存儲器(和另一個24 bytes其包裹Func<T>,假設32位處理),和一個Lazy<T>實例的創建是實際上不含。所以不必擔心這一點,除非你在一個內存限制嚴格的環境中。

而且如果內存消耗是一個問題,請嘗試註冊使用壽命大於瞬態的服務。您可以根據請求,每個Web請求或單例執行操作。我甚至會說,當你在創建新對象的環境中出現問題時,你應該只使用單例服務(但是由於你正在構建Web應用程序,所以你不太可能在這樣的環境中工作) 。

請注意,Ninject是.NET較慢的DI庫之一。如果這讓你煩惱,switch to a faster container。一些容器的性能接近手工繪製對象圖。 但是無論如何,請仔細分析這一點,許多開發人員因錯誤的原因切換DI庫。

請注意,使用Lazy<T>作爲依賴項是leaky abstraction(違反了Dependency Inversion Principle)。請閱讀this answer瞭解更多信息。

+0

謝謝。你讓我對情況的理解更加清晰。 – xwrs

+0

我不認爲這是過早的優化,有了這個參數,它似乎永遠不需要懶惰,創建一個對象不重,但你不知道它在它的構造函數中創建了多少個對象。並打開一些不可用的遠程資源。 –

0

史蒂芬是說,這看起來像過早的優化是正確的。這些對象的構建速度非常快,通常不會成爲瓶頸。

但是,使用Lazy來表達您不需要的依賴項是依賴注入框架中的常見模式。 Actofac就是一個這樣的容器,它的內置支持various wrapping types。我相信Ninject也有一個擴展,也許看看這個,Ninject Lazy

+1

DI容器支持懶惰這一事實並不能讓您的應用程序代碼依賴於惰性依賴關係。許多DI容器支持不推廣最佳實踐的功能。從依賴注入的角度來看,懶惰是一個漏洞抽象。請閱讀[this](https://stackoverflow.com/a/21724609/264697),瞭解爲什麼Lazy 泄漏的原因。 – Steven