2011-08-04 89 views
16

如何將構造函數注入與「手動」構造函數參數結合起來?即。結合DI與構造函數參數?

public class SomeObject 
{ 
    public SomeObject(IService service, float someValue) 
    { 
    } 
} 

在哪裏IService應該被我的DI容器解決/注入,並且應該指定someValue。我如何混合兩者?

+0

通過手動構造函數參數,您是指當您手動構造類而不是DI時,或者您的意思是DI容器傳遞參數。如果它的前者,那麼你可以做一個構造函數重載? – lahsrah

+0

無論什麼情況我總是需要IService,所以我認爲我不能只是重載,沒有依賴,它神奇地使用完整的構造函數(除非我使用ServiceLocator - yuck!)。 –

回答

13

這樣的構建應儘可能避免。因此,問問自己:這個參數是否真的需要作爲構造函數參數?或者可以將SomeObject替換爲無狀態的對象,每個依賴於它的人都可以通過將該參數傳遞給在對象上執行的方法來重用它?

例如取而代之的

public class SomeObject 
{ 
    private float someValue 
    public SomeObject(IService service, float someValue) 
    { 
     this.someValue = someValue 
    } 

    public float Do(float x) 
    { 
     return this.Service.Get(this.someValue) * x; 
    } 
} 

使用

public class SomeObject 
{ 
    public SomeObject(IService service) 
    { 
    } 

    public float Do(float x, float someValue) 
    { 
     return this.Service.Get(someValue) * x; 
    } 
} 

如果需要去工廠:

public interface ISomeObjectFactory 
{ 
    ISomeObject CreateSomeObject(float someValue); 
} 

public class SomeObjectFactory : ISomeObjectFactory 
{ 
    private IKernel kernel; 
    public SomeObjectFactory(IKernel kernel) 
    { 
     this.Kernel = kernel; 
    } 

    public ISomeObject Create(float someValue) 
    { 
     return this.kernel.Get<ISomeObject>(WithConstructorArgument("someValue", someValue); 
    } 
} 

前瞻: Ninject 2.4,將不需要執行了,但允許

kernel.Bind<ISomeObjectFactory>().ToFactory(); // or maybe .AsFactory(); 
+0

+1絕對避免是正確的答案,編輯我的答案同意。我知道它會稍微隱藏一點,但正如其他地方所討論的,考慮用Func ctor arg而不是直接使用內核來表達你的SomeObjectFactory –

+0

@Ruben Bartelink:我剛剛成功了這個版本,因爲我認爲它會成爲首選Ninject 2.4。工廠將由內核自動生成。 Func變體也將得到支持,缺點是Func不提供有關參數的信息,並且使參數匹配更加困難。因此,我不再堅持使用Func變體,只需刪除工廠實現並更改綁定即可進行更新。但是,我也會把工廠放到引導程序中,而把用戶的接口放在旁邊。 –

+0

感謝您解釋Func注射的微妙之處 - 沒有想到通過。我只是提出一個觀點,即在Factory的2.4版本中,你正在使用一個Func來代替內核。現在想一想,這樣做會使答案變得不那麼清晰,並且不會映射ToFactory將要做的事情。所以忘記我說的話,謝謝你解釋!它是su_gg_est:P順便說一句,你錯誤地輸入了方法名稱作爲Create(而不是CreateSomeObject)。我個人會優先使用Func,因爲我生活在一個混淆的世界...... –

1

如果「someValue中」永遠是恆定的,那麼你可以在你與容器註冊類型,因爲它在後下

See Here

解釋,但認爲使用InjectionParameters的,如果這是不正確的,比解析實例時沒有辦法確定參數值,您可能會想到將「someValue」從構造函數中移出並使其成爲該類的一個屬性。

0

我可能會使用一個天真的解決方案。如果您在需要時知道someValue的值,我會將其從構造函數中移除並將屬性添加到對象中,以便您可以設置someValue。通過這種方式,您可以從容器中獲取對象,然後在有對象時設置該值。

我的另一個建議是,你不是直接訪問它,而是創建一個工廠,你可以用它來創建這樣的對象。然後,將工廠註冊到容器中,並使用工廠創建實例。像這樣的:

public class SomeObjectFactory : ISomeObjectFactory 
{ 
    private IYourService _service; 
    public SomeObjectFactory(IYourService service) 
    { 
     _service = service; 
    } 

    public ISomeObject Create(float someValue) 
    { 
     return new SomeObject(_service, someValue); 
    } 
} 

你可以嘗試一個這樣的模式。

更新:更新了代碼以反映改進評論。

+0

您似乎對'SomeObjectFactory'中的選擇容器有很強的依賴性。這並未被廣泛推薦。相反,將'IYourService'實例注入到'SomeObjectFactory'構造函數中,並讓conatiner解析組合根中的依賴關係。 –

+0

當然,我的代碼只是一個提綱,並不是最終的實現。關鍵是他應該使用工廠。但我根據我的意思更新了代碼。 –

+0

好多了! :) –

1

你真的不應該嘗試使用D.I.爲了這。你可以想出所有類型的古怪的解決方案,但他們可能沒有道理。

我們的方法是通過D.I.創建一個工廠,然後工廠的Create方法將使用D.I.中傳入的方法自行創建。容器。我們不必經常使用這種模式,但是當我們這樣做時,實際上會使產品更清潔(因爲它使我們的依賴關係圖變小)。