2015-07-10 167 views
2

Arrrgh!我正在這裏拉我的頭髮。我一直在嘗試使用IoC容器,並且一切看起來都很好,並且很棒,直到遇到一些您認爲非常基本的問題,例如將參數傳遞給構造函數。如何在使用IoC容器時將參數傳遞給構造函數?

說我有與引用類可以由IOC和值類型(或一些其他類型的)來解決的混合某處的類,它可以只在運行時被解決:

public NFLFeedUnitOfWork(NFLFileType fileType, object feed, IConverterMappings<NFLFileType> nflConverterMappings, IDbContext context) 
    : base(fileType, feed, nflConverterMappings, context, ContextType.NFL) 
{ 
    //new NFLContext(connstringname, setAutoDetectChanges) 
} 

在該特定示例我傳入枚舉(NFLFileType),對象實例,2個接口參數,並將一個額外的硬編碼屬性傳遞給基礎構造函數(ContextType.NFL)

如何在任何IoC容器中都可以做到這一點?

這個問題實際上是2倍:

1)如何在其僅在運行時已知的物體通過了嗎?舉例來說,此時的呼叫代碼如下所示:

protected override IFeedUnitOfWork GetUnitOfWork(NFLFileType fileType, object feed, string connectionString) 
{ 
    return new NFLFeedUnitOfWork(fileType, feed, new NFLConverterMappings(), new NFLContext(connectionString)); 
} 

如何將此代碼轉換爲使用IoC? 也許是這樣的?

protected override IFeedUnitOfWork GetUnitOfWork(NFLFileType fileType, object feed, string connectionString) 
{ 
    return IFLFeedUnitOfWork(fileType, feed); 
} 

哪裏最後2個參數自動解決,並且自己提供1st 2 I?

2.)我如何傳入枚舉,對象,值類型到構造函數使用IoC? (或者可能不會在這個特定的情況下使用它?)

無論如何,任何幫助非常感謝,特別是在第一點。 此刻我正在使用Unity,但任何其他IoC容器也不錯。

我不想將IoC容器傳入代碼中,我只想在頂層的一個地方指定它。

回答

1

您有幾個不同的選項,具體取決於值的來源。 (我只熟悉Ninject,我認爲Unity具有類似的功能)

如果數據依賴於另一個服務或存儲庫,則可以將該對象綁定到委託,以便在請求滿足時解析它。例如:

Bind<NFLFileType>().ToMethod(context => context.Kernel.Get<IConfigProvider>().NFLFileType); 

Ninject還支持綁定,只有在使用​​語法某些情況下解決。例如:

Bind<NFLFileType>().ToConstant(NFLFileType.MyValue).WhenInjectedInto<NFLFeedUnitOfWork>(); 

Bind<NFLFileType>().ToConstant(NFLFileType.MyValue).When(request => request.Target.Type.GetCustomAttributes(typeof(MyValueAttribute)) != null); 

如果一切都失敗時,可以將注入的接口,可以像一個工廠模式提供者生成對象:

Bind<IFeedUnitOfWork>().ToProvider<UnitOfWorkProvider>(); 

和提供者知道如何解決前兩個基於上下文的參數。

HTH。

5

我有的引用類的混合,可以是 IOC和值類型(或一些其他類型的)解決某處一類只能 解決在運行時

這是你出錯了。編寫組件時,不應將編譯時間依賴性與運行時數據混合在一起。您的對象圖應該是靜態的(並且最好是無狀態的),運行時數據應該在完成對象圖構建後使用方法調用通過對象圖傳遞。這可以在應用程序的開發中引起極大的簡化,因爲它可以靜態驗證對象圖形(使用工具,單元測試或使用Pure DI),並且可以防止您今天遇到麻煩。

一般情況下,你有兩個選擇來解決這個問題:

  1. 您通過方法調用傳遞到較低級別的組件中的數據。
  2. 您可以通過調用注入組件上的方法來檢索數據。

要採取的解決方案取決於上下文。

如果數據是特定於處理的請求並且是您正在處理的用例的一部分,您通常會選擇一個選項。例如:

public interface IFeedUnitOfWorkProvider 
{ 
    IFeedUnitOfWork GetUnitOfWork(NFLFileType fileType, object feed); 
} 

這裏IFeedUnitOfWorkProvider包含GetUnitOfWork方法需要運行時參數作爲輸入。一個實現可能是這樣的:

public class FeedUnitOfWorkProvider : IFeedUnitOfWorkProvider 
{ 
    private readonly IConverterMappings converterMappings; 
    private readonly IContext context; 

    public FeedUnitOfWorkProvider(IConverterMappings converterMappings, 
     IContext context) { 
     this.converterMappings = converterMappings; 
     this.context = context; 
    } 

    public IFeedUnitOfWork GetUnitOfWork(NFLFileType fileType, object feed) { 
     return new NFLFeedUnitOfWork(fileType, feed, this.converterMappings, 
      this.context); 
    }  
} 

有幾件事情,這裏要注意:

  • 所有靜態已知依賴關係通過構造函數注入,而運行時的值是通過方法調用注入。
  • connectionString的值不知道FeedUnitOfWorkProvider。它不是直接的依賴關係,提供者不必知道它的存在。
  • 假設connectionString是一個在運行時不會更改的配置值(通常存儲在應用程序的配置文件中),它可以注入到NFLContext中,與注入其他依賴關係相同。請注意,配置值與運行時值不同,因爲它在應用程序的生命週期中不會更改。

第二個選項,當你在處理上下文信息是非常有用的。這是對實現很重要的信息,但不應像前面的示例那樣傳遞。這方面的一個很好的例子是關於代表請求運行的用戶的信息。典型的抽象如下:

public interface IUserContext { 
    string CurrentUserName { get; } 
} 

此接口可以注入任何消費者。使用這個抽象,消費者可以在運行時查詢用戶名。用其他請求數據傳遞用戶名通常會很尷尬,因爲這會讓調用者更改(或忘記)用戶名,使得代碼更難以使用,更難以測試,更容易出錯。相反,我們可以使用IUserContext

public IFeedUnitOfWork GetUnitOfWork(NFLFileType fileType, object feed) { 
    if (this.userContext.CurrentUserName == "steven") { 
     return new AdminUnitOfWork(this.context); 
    } 
    return new NFLFeedUnitOfWork(fileType, feed, this.converterMappings, 
     this.context); 
} 

如何一個IUserContext實現應該看起來像將高度依賴於應用程序正在構建的類型。對於ASP.NET我想像這樣:

public class AspNetUserContext : IUserContext { 
    string CurrentUserName { 
     get { return HttpContext.Current.User.Name; } 
    } 
} 
+2

+1。這顯示了OP的痛點並提供了很好的建議。 Unity還可以提供ResolverOverrides,以便在解析時覆蓋現有註冊(如[使用覆蓋解析對象](https://msdn.microsoft.com/en-us/library/ff660920(v = pandp 0.20)的.aspx))。我毫不猶豫地提到這一點,因爲我認爲上述建議應該是第一種方法。 –

+0

這樣一個很好的答案!非常感謝Steven,這絕對回答了我的大部分問題,並指出了我的正確方向。但是你能澄清一下嗎?在案例1提供的例子中,我們基本上爲調用'GetUnitOfWork'方法的類創建了一個Provider。然而,在'GetUnitOfWork'本身的實現中,我們仍然將僅在運行時已知的2個值傳遞給'new NFLFeedUnitOfWork(...'這是否意味着我還需要爲'NFLFileType fileType'和'object創建另外2個提供者(這似乎有點太多,1個運行時值的提供者) – Tanuki

+0

@Tanuki:我無法回答這個問題,我不知道那些vakues是什麼,以及它們是如何確定的。與這方面的信息,我會嘗試看看。 – Steven