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

Register singletons as collection of Interfaces with Prism 7

我正在将使用 MEF for IOC 的 Prim 6 转换为 Prism 7 Unity,因为不再支持 MEF。我必须应对的最大差异是 MEF 中的假设,即默认情况下一切都是单例,而 Unity 倾向于假设相反。

我已经转换了大部分,但我 运行 做的一件事是让构造函数通过集合引用单例。例如,我有这些接口和 类:

public interface IAppService { }

public interface IDebugService : IAppService { }
public class DebugService : IDebugService { }

public interface IOtherService : IAppService { }
public class OtherService : IOtherService { }

with DebugService and OtherService registers as singletons and mapped to both of their respective interfaces:

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 是 registered/mapped 作为单例的 return 相同的实例但是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 升级到预览版不会有什么不同,因为它仍然引用相同的统一版本。但是更新统一包会破坏 Prism,因为它们包含制动更改(看起来像 Unity.Abstraction)。


感谢 HAUKINGER 的回答

Haukinger 让我走上了正确的轨道,如果这有帮助,请给他点赞!!

由于 prism 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

编辑:有点复杂,解决方案看起来有点workaround-ish...

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。根据您的统一版本,您 can/have 使用 InjectionFactory 而不是 RegisterFactory