說實話,我會盡量避免在構造函數中有一個原始類或難以解析類的類設計。正如你已經從Tavares的回答中看到的那樣,你的配置變得非常脆弱(更新:Tavares似乎已經刪除了他的回答,原因是我不清楚)。您會減少編譯時支持,並且每次更改該構造函數都會使您更改DI配置。
有多種方法可以更改您的設計以防止出現這種情況。哪一個是適用於你的是你的,但這裏有一些想法:
方法1:使用一個不變的配置DTO:
private sealed class LoginManagerConfiguration
{
public Uri Login { get; private set; }
public Uri Target { get; private set; }
public string MainRegionName { get; private set; }
public LoginManagerConfiguration(Uri login, Uri target, string mainRegionName)
{
this.Login = login;
this.Target = target;
this.MainRegionName = mainRegionName;
}
}
現在你可以讓你的LoginManager
採取的依賴LoginManagerConfiguration
:
public LoginManager(IRegionManager regionManager,
IEventAggregator eventAggregator,
LoginManagerConfiguration configuration)
{
...
}
的LoginManagerConfiguration
可以簡單地註冊這樣的:
container.RegisterInstance<LoginManagerConfiguration>(
new LoginManagerConfiguration(
login: new Uri("Login"),
target: new Uri("Target"),
mainRegionName: ConfigurationManager.AppSettings["MainRegion"]));
指定應用程序範圍的配置對象而不是特定類型的DTO可能很誘人,但這是一個陷阱。這種應用程序範圍的配置對象是服務定位器反模式的配置等同物。變得不清楚類型需要什麼樣的配置值,並使得類難以測試。
選項2:從該類
另一種選擇是從類派生推導,只是爲了DI構造的目的。當你不能改變類簽名,這是特別有用的(即當它是一個第三方組件):
private sealed class DILoginManager : LoginManager
{
DILoginManager(IRegionManager regionManager,
IEventAggregator eventAggregator)
: base(regionManager, eventAggregator,
ConfigurationManager.AppSettings["MainRegion"],
new Uri("Login"),
new Uri("Target"))
{
...
}
}
定義這個類接近你的應用程序的組成根源。該類成爲DI配置的實現細節。你的類型的註冊,現在將是非常簡單的:
container.RegisterType<ILoginManager, DILoginManager>();
要非常小心,雖然與調用,延遲加載配置值,如ConfigurationManager.AppSettings["MainRegion"]
。這很容易導致在應用程序啓動過程中配置錯誤未被捕獲的情況,這確實是最好的。
方法3:使用一個工廠委託
最後的選擇我想現在是一個工廠。這看起來非常像Traveses的答案,但是更安全:
var mainRegion = ConfigurationManager.AppSettings["MainRegion"];
container.Register<ILoginManager>(new InjectionFactory(c =>
{
return new LoginManager(
c.Resolve<IRegionManager>(),
c.Resolve<IEventAggregator>(),
ConfigurationManager.AppSettings["MainRegion"],
new Uri("Login"),
new Uri("Target"));
}));
我希望這有助於。
對於InjectionFactory方法,您還可以註冊一個類型爲Func的關聯接受這些參數的InjectionFactory並返回一個ILoginManager,如下所示:new InjectionFactory(c =>(login,target ,mainRegionName)=> c.Resolve (新的ParameterOverride(「mainRegionName」,mainRegionName),新的ParameterOverride(「login」,登錄),新的ParameterOverride(「target」,target))))。通過這種方式進行解析,您可以在構造函數中保持依賴關係的靈活性,並且只需對基本參數更改進行更改即可。 –
2011-06-01 22:03:33
非常好的答案,順便說一句。 – 2011-06-01 22:03:52
忘記添加:使用方法是,您可以接受Func作爲依賴項,並將這些參數傳遞給該函數,從而生成ILoginManager。如果這些是設置,我會堅持使用Steven的方法,但是如果它們的運行時值可能會在某些情況下發生變化,那麼您可能需要這樣做。 –
2011-06-01 22:06:01