我有一个类在其构造函数中有一些原始类型参数,如字符串等.
我应该如何使用统一容器注册类型?
public LoginManager( IRegionManager regionManager,IEventAggregator eventAggregator,string mainRegionName,Uri login,Uri target) { this.regionManager = regionManager; this.eventAggregator = eventAggregator; this.mainRegionName = mainRegionName; this.login = login; this.target = target; } }
更新:
请记住,IRegionManager和IEventAggregator是Prism UnityBootstrapper的已知类型,在我的情况下是容器包装器.我必须重新注册吗?我想保持类型注册尽可能简单.
这会被视为坏习惯吗?有更好的选择吗?
解决方法
尝试防止在构造函数中具有原始或难以解析类型的类设计.正如你已经从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,LoginManagerConfiguration configuration) { ... }
LoginManagerConfiguration可以像这样注册:
container.RegisterInstance<LoginManagerConfiguration>( new LoginManagerConfiguration( login: new Uri("Login"),target: new Uri("Target"),mainRegionName: ConfigurationManager.AppSettings["MainRegion"]));
指定应用程序范围的配置对象而不是此类型特定的DTO可能很诱人,但这是一个陷阱.这种应用程序范围的配置对象是Service Locator反模式的配置等价物.不清楚类型需要什么配置值,并使类更难测试.
选项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>(),new Uri("Target")); }));