说实话,我会尽量避免在构造函数中有一个原始类或难以解析类的类设计。正如你已经从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