Зарегистрируйте синглтоны как набор интерфейсов с Prism 7 - PullRequest
3 голосов
/ 20 мая 2019

Я преобразую Prim 6, используя MEF для IOC, в 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 { }

с 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);
}

Цельis 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, то это будет только один раз.Как я могу иметь один и только один экземпляр сервисов, но при этом регистрировать их с другими интерфейсами для получения в виде коллекций.


ОБНОВЛЕНИЕ

Благодаря ответу ХокингераЯ взглянул на github Prism, так как эта перегрузка не отображается модулем.Оказывается, они добавляют это в 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

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>())
);

1 Ответ

2 голосов
/ 21 мая 2019

Если вы регистрируетесь временно, как это

containerRegistry.Register<IAppService, DebugService>(typeof(DebugService).FullName);

, тогда разрешается новый DebugService каждый раз, когда ожидается поведение.

Есливы хотите, чтобы существовал только один DebugService экземпляр, зарегистрируйте его как синглтон:

containerRegistry.RegisterSingleton<IAppService, DebugService>(typeof(DebugService).FullName);

Для подробного описания того, что Unity 5 делает здесь и почему это делает (в отличие от более старых версий), посмотрите на эта вики-страница на github .

РЕДАКТИРОВАТЬ: это немного сложнее, и решение выглядит немного обходным путем ...

container.RegisterSingleton<Service>();
container.RegisterFactory<ISingleInterface>( x => x.Resolve<Service>() );
container.RegisterFactory<IEnumeratedInterface>( "service", x => x.Resolve<Service>() );

Этовсе для IUnityContainer, вы должны получить его из IContainerRegistry, используя расширение GetContainer().

Дальнейшее чтение в github Unity .В зависимости от версии Unity вы можете / должны использовать InjectionFactory вместо RegisterFactory.

...