由于不再支持MEF,因此我正在使用用于IOC的MEF将Prim 6转换为Prism 7 Unity.我必须解决的最大区别是,MEF中的假设是默认情况下所有内容都是单例的,而Unity则相反.
我已将大多数转换,但是我遇到的一件事是让构造函数通过集合引用单例.例如,我有以下接口和类:
public interface IAppService { }
public interface IDebugService : IAppService { }
public class DebugService : IDebugService { }
public interface IOtherService : IAppService { }
public class OtherService : IOtherService { }
使用DebugService和OtherService注册为单例并映射到它们各自的两个接口:
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IModuleMessageBus, ModuleMessageBus>();
containerRegistry.RegisterSingleton<DebugService>();
containerRegistry.RegisterSingleton<IDebugService, DebugService>();
containerRegistry.Register<IAppService, DebugService>(typeof(DebugService).FullName);
containerRegistry.RegisterSingleton<OtherService>();
containerRegistry.RegisterSingleton<IOtherService, OtherService>();
containerRegistry.Register<IAppService, OtherService>(typeof(OtherService).FullName);
}
目的是将DebugService / IDebugService和OtherService / IOtherService注册/映射为单例,这将返回相同的实例,但IAppService作为每个实例的命名实例,因此可以注册一个以上的IAppService.任何获取集合的调用都将包含DebugService和OtherService的单例.
第二部分是给我一个问题.在构造函数中获取IAppService的集合总是会生成新的实例.所以,如果我有这个:
public SomeViewModel(
IModuleMessageBus messageBus
, IDebugService debugService
, IEnumerable<IAppService> services
) { }
public AnotherViewModel(
IModuleMessageBus messageBus
, IDebugService debugService
) { }
将会发生的情况是DebugService的构造函数将被击中两次.一次是为两个构造函数的IDebugService注入,另一次是为IEnumerable的注入.如果我注释掉,则IEnumerable< IAppService>服务,那么它只会被击中一次.如何拥有一个服务实例和一个服务实例,但仍要向其他接口注册它们以获得集合.
更新
感谢Haukinger的响应,我看了Prism的github,因为该重载没有被模块暴露.原来他们在7.2中添加了它.它的最新预览(截至撰写本文时已满5天)已合并到:
https://github.com/PrismLibrary/Prism/pull/1668
更新2
不幸的是,这似乎仍然是一个问题.我将注册更改为此,但仍然被击中两次:
containerRegistry.RegisterSingleton<DebugService>();
containerRegistry.RegisterSingleton<IDebugService, DebugService>();
containerRegistry.GetContainer().RegisterSingleton(
typeof(IAppService)
, typeof(DebugService)
, typeof(DebugService).FullName
);
containerRegistry.RegisterSingleton<OtherService>();
containerRegistry.RegisterSingleton<IOtherService, OtherService>();
containerRegistry.GetContainer().RegisterSingleton(
typeof(IAppService)
, typeof(OtherService)
, typeof(OtherService).FullName
);
将PRISM升级到预览不会有什么区别,因为它仍然引用相同的统一版本.但是更新unity软件包会破坏Prism,因为它们包含制动更改(看起来像Unity.Abstraction中的样子).
谢谢哈金格
豪金格(Haukinger)使我走上了正确的轨道,因此如果有帮助,请给他撞个撞!
由于棱镜7(当前)使用的是Unit Container 5.8 / Unity Abstraction 3,因此我们必须使用被标记为已过时且即将被删除的InjectionFactory.为了使上述工作正常进行,我必须这样做(很糟糕):
containerRegistry.RegisterSingleton<DebugService>();
containerRegistry.RegisterSingleton<IDebugService, DebugService>();
//Manually map the registration resolve
containerRegistry.GetContainer().RegisterType<IAppService>(
typeof(DebugService).FullName
, new InjectionFactory(c => c.Resolve<DebugService>())
);
containerRegistry.RegisterSingleton<OtherService>();
containerRegistry.RegisterSingleton<IOtherService, OtherService>();
//Manually map the registration resolve
containerRegistry.GetContainer().RegisterType<IAppService>(
typeof(OtherService).FullName
, new InjectionFactory(c => c.Resolve<OtherService>())
);
解决方法:
如果您这样临时注册
containerRegistry.Register<IAppService, DebugService>(typeof(DebugService).FullName);
然后每次都应解决一个新的DebugService的预期行为.
如果只希望存在一个DebugService实例,请将其注册为单例:
containerRegistry.RegisterSingleton<IAppService, DebugService>(typeof(DebugService).FullName);
有关Unity 5在这里做什么以及为什么这样做的详细说明(与旧版本不同),请查看this wiki page on github.
编辑:这有点复杂,并且解决方案看起来相当多的替代方法…
container.RegisterSingleton<Service>();
container.RegisterFactory<ISingleInterface>( x => x.Resolve<Service>() );
container.RegisterFactory<IEnumeratedInterface>( "service", x => x.Resolve<Service>() );
这全部用于IUnityContainer,您必须使用GetContainer()扩展从IContainerRegistry获取它.
进一步阅读at unity’s github.根据您的统一版本,您可以/必须使用InjectionFactory而不是RegisterFactory.