使用基元参数构造函数注册类型
本文关键字:构造函数 注册 类型 参数 | 更新日期: 2023-09-27 17:56:44
我有一个类,它的构造函数中有一些原始类型参数,例如字符串等。
我应该如何将类型注册到 unity 容器?
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的已知类型,在我的情况下是容器包装器。我必须重新注册它们吗?我想使类型注册尽可能简单。
这会被认为是一个坏习惯吗?还有更好的选择吗?
尽量防止类设计在构造函数中具有原始或难以解析的类型。正如你已经从塔瓦雷斯的回答中看到的那样,你的配置变得非常脆弱(更新:塔瓦雷斯似乎已经删除了他的答案,原因我不清楚)。您失去了编译时支持,对该构造函数的每次更改都会使您更改 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"));
}));
这不是一个坏习惯。这是一个完全有效的方案。自从我离开 Unity 以来已经有几年了,但从我的头顶上,您必须明确指向您想要的构造函数并枚举所有参数,对于原始参数,new ResolvedParameter("your value")
.
我还注意到你那里有一个Type
参数。对 Unity 要谨慎,因为它有一个...处理这些非常令人惊讶的方式。我有一篇博客文章在这里详细介绍了这一点。