由于不再支持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> services
注释掉,则只会被点击一次。如何拥有一个服务实例和一个服务实例,但仍要在其他接口中注册它们以获得集合。
更新
由于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(当前)正在使用单元容器5.8 / Unity抽象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>())
);
答案 0 :(得分:2)
如果您这样临时注册
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
的全部内容,您必须使用IContainerRegistry
扩展名从GetContainer()
获取。
进一步阅读at unity's github。根据您的统一版本,您可以/必须使用InjectionFactory
而不是RegisterFactory
。