78

我使用微軟的Unity依賴注入和我想要做這樣的事情:我可以將構造函數參數傳遞給Unity的Resolve()方法嗎?

IDataContext context = _unityContainer.Resolve<IDataContext>(); 
var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context 
var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context 

IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance 
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2); 

RepositoryARepositoryB都有一個構造函數的IDataContext參數,我想統一初始化與上下文信息庫我通過它。還請注意,IDataContext未註冊Unity(我不想要3個IDataContext)。

回答

33

< 2美分>

如果您稍後決定使用不同的服務,需要什麼不僅僅是方面多還是少?

構造函數參數和IoC的問題是參數最終綁定到正在使用的具體類型,而不是服務接口定義的合約的一部分。

我的建議是你要麼解決上下文,我相信Unity應該有一種方法讓你避免構建它的3個實例,或者你應該考慮一個工廠服務,它有一個方法來構造物體。例如,如果您稍後決定構建一個根本不依賴傳統數據庫的存儲庫,而是使用XML文件爲測試生成虛擬數據,會出現什麼情況呢?如何將XML內容提供給構造函數?

IoC基於解耦代碼,通過將參數的類型和語義綁定到具體類型,您確實沒有正確解耦,仍然存在依賴關係。

「此代碼可以與任何類型的存儲庫進行通信,只要它實現此接口....哦,並使用數據上下文」。

現在,我知道其他的IoC容器都支持這個功能,而且我也在自己的第一個版本中使用了它,但在我看來,它並不屬於解決步驟。

</2美分>

+3

我明白你的意思,並同意你的觀點,但是我仍然需要RepositoryA和RepositoryB的情況下,具有相同的IDataContext,這需要比RepositoryC不同。另請注意,IRepositoryA和IRepositoryB具有IDataContext的屬性。我會稍微更新示例代碼。 – NotDan 2009-04-24 19:24:48

+2

偉大的一點。我正要爲構造函數添加一個字符串參數,但在查看了這一點之後,我決定將其設置爲一個完整的對象。它只包含此時的字符串,但我已經可以看到如何向其添加更多有用的屬性 – 2010-07-09 09:52:37

0

NotDan,我想你可以在註釋中lassevk已經回答了你自己的問題。

首先,我將使用LifetimeManager來管理Unity創建的IDataContext實例的生命週期和數量。
http://msdn.microsoft.com/en-us/library/cc440953.aspx

聽起來像ContainerControlledLifetimeManager對象會給你你需要的實例管理。使用該LifetimeManager後,Unity應該將IDataContext的相同實例添加到需要IDataContext依賴項的所有對象。

3

很簡短的答案是:不。 Unity目前沒有辦法將參數傳遞到構造函數中,這些參數並不是常量或注入的,我一直都能找到。恕我直言,這是它最大的缺陷,但我認爲這是通過設計而不是遺漏。根據Jeff Fritz的說法,你可以在理論上創建一個定製的生命週期管理器,該管理器知道哪個上下文實例要注入到各種類型中,但這是一個硬編碼級別,它似乎可以避免在Unity中使用Unity或DI的目的。第一名。

您可以從完整的DI中退出一小步,並讓您的存儲庫實現負責建立自己的數據上下文。上下文實例仍然可以從容器中解析出來,但決定使用哪一個的邏輯必須進入存儲庫的實現。這當然不是那麼純粹,但它會擺脫這個問題。

1

您可以使用(真的不知道,如果它是一個很好的做法或不)是創建兩個容器和註冊一個實例爲每個另一種選擇:

IDataContext context = _unityContainer.Resolve<IDataContext>(); 
_unityContainer.RegisterInstance(context); 
var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context 
var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context 


//declare _unityContainer2 
IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance 
_unityContainer2.RegisterInstance(context2); 
var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance 

希望這有助於太

7

您可以使用InjectionConstructor/InjectionProperty/InjectionMethod取決於ResolvedParameter < T內部的注射架構>( 「名」 )獲取容器中預先註冊的對象的實例。

在你的情況下,這個對象必須註冊一個名稱,對於相同的實例,你需要將ContainerControlledLifeTimeManager()作爲LifeTimeManager。

_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager()); 
_unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB"); 

    var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA"))); 

    var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA"))); 

    var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextB"))); 
5

謝謝你們......我的帖子與「Exist」類似。請看下圖:

 IUnityContainer container = new UnityContainer(); 
     container.LoadConfiguration(); 

     _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[] 
     { 
      new ParameterOverride("activeDirectoryServer", "xyz.adserver.com") 
     }); 
相關問題