用Prism 7将单例注册为接口集合

时间:2019-05-20 19:16:34

标签: c# unity-container prism ioc-container prism-7

由于不再支持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 { }

使用DebugServiceOtherService注册为单例并映射到它们各自的两个接口:

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 / IDebugServiceOtherService / IOtherService被注册/映射为单例,它们将返回与命名实例相同的实例,但返回IAppService每个都可以注册一个IAppService。任何获取集合的调用都将包含DebugServiceOtherService的单例。

第二部分是给我一个问题。在构造函数中获取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>())
);

1 个答案:

答案 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