Unity:使用一个接口的两个实现解析类
本文关键字:两个 实现 一个 Unity 接口 | 更新日期: 2023-09-27 18:34:31
我的结构如下:
static void Main(string[] args) {
var container = new UnityContainer();
container.RegisterType<IBaseService, ServiceA>("a");
container.RegisterType<IBaseService, ServiceB>("b");
container.RegisterType<IWorker, Worker>();
var runner = container.Resolve<Runner>();
/* ... */
}
public class Runner {
public Runner(IWorker worker) {}
}
public class Worker : IWorker {
public Worker(IBaseService a, IBaseService b) { /* ... */ }
}
public class ServiceA : IBaseService {}
public class ServiceB : IBaseService {}
我知道我可能会为 ServiceA 设置其他接口,例如 IServiceA(与 ServiceB - IServiceB 相同(并将它们注册到容器中。但是,是否有可能解决具有相同协定IBaseService的两个服务的Worker 实例(第一个参数应该得到ServiceA,第二个参数应该得到ServiceB(,或者这会导致某种歧义?
如果您尝试按照发布的方式运行代码,您将收到异常:
当前类型IBaseService是一个接口 并且无法构建。是否缺少类型映射?
这是因为在 IBaseService 的容器中没有注册默认注册(默认含义为没有名称(。 仅注册了两个命名接口映射。
处理这种情况的方法很少。 正如@Haukinger所提到的,一种方法是将所有IBaseService实现注入到对象中。
所以你可以像这样声明你的类:
public class Worker2 : IWorker
{
public Worker2(IEnumerable<IBaseService> baseServices)
{
/* ... */
}
}
然后像这样向容器注册:
container.RegisterType(typeof(IEnumerable<IBaseService>), typeof(IBaseService[]));
这会将IEnumerable<IBaseService>
映射到有效的IBaseService
数组,因为当 Unity 看到一个数组时,它将注入使用所有命名注册并将其注入到对象中。您也可以直接使用数组,而无需 IEnumerable 映射。
这种方法可能很有用,但通常你想知道正在注入哪种类型(例如,必须在运行时根据其他一些条件选择正确实现的工厂(。
另一种方法是将 Unity 配置为将正确的命名注册注入工作线程:
container.RegisterType<IWorker, Worker>(
new InjectionConstructor(
new ResolvedParameter<IBaseService>("a"),
new ResolvedParameter<IBaseService>("b")));
在上面的例子中,我们告诉 Unity 要使用什么构造函数以及注入哪个实现。
另一种方法是使用 InjectionFactory:
container.RegisterType<IWorker, Worker>(
new InjectionFactory(
c => new Worker(c.Resolve<IBaseService>("a"), c.Resolve<IBaseService>("b"))
));
使用 InjectionFactory 的一个好处是,因为我们正在更新 Worker 对象,所以我们可以对构造函数进行编译器检查。 例如,如果更改了 Worker 构造函数以添加新参数,则会出现编译错误。 相反,InjectionConstructor 方法可以编译,但会生成运行时错误System.InvalidOperationException: The type Worker does not have a constructor that takes the parameters (IBaseService, IBaseService).