Prism 7 - внедрение объектов IContainer в модель представления - PullRequest
0 голосов
/ 19 октября 2018

Недавно у меня была возможность создать новое приложение на основе призмы.Я использовал версию 6.3 довольно долго, но увидел, что призма 7 вышла из предварительной версии и хотела попробовать.Я создал новое приложение Prism, используя пакет шаблонов Prism, и все работало как положено из коробки.Я обновил модель представления, как это обычно делается в 6.3, для передачи в Контейнер, чтобы я мог разрешить некоторые объекты, которые позднее предоставили бы информацию для представления, в 6.3 я бы сделал следующее:

public MainWindowViewModel(IRegionManager aRegionManager,
                           IUnityContainer aUnityContainer) : base()

Теперь в 7.1.0.431 я попытался сделать то же самое, но обновил интерфейсы для учета новой абстракции IOC.

public MainWindowViewModel(IRegionManager aRegionManager,
                           IContainerProvider aContainerProvider,
                           IContainerRegistry aContainerRegistry) : base()

Это создает исключение из ViewModelLocator.AutoWireViewModel для параметров IContainerX.

System.Exception {Unity.Exceptions.ResolutionFailedException}

{"Resolution of the dependency failed, type = 'Sample.ViewModels.MainWindowViewModel', name = '(none)'.\nException occurred while: while resolving.\nException is: InvalidOperationException - The current type, Prism.Ioc.IContainerProvider, is an interface and cannot be constructed. Are you missing a type 

Это действует так, как будто я пропускаю ссылку, но этот тип передается в вызов RegisterTypes приложения, поэтому все ссылки должны быть найдены.Я делаю что-то не так для новой версии 7.X?

РЕДАКТИРОВАТЬ: Per @ mnistic

Вот код из пакета шаблонов, предоставленного App.xaml.csгде передается IContainerRegistry.

  protected override void RegisterTypes(IContainerRegistry containerRegistry)
  {
      //containerRegistry is a valid instance here
  }

Обновление :

Немного больше, IContainerRegistry, который был передан в RegisterTypes, перечисляет все типы / интерфейсыкоторые доступны на момент вызова метода.Он имеет зарегистрированный экземпляр IUnityContainer.Я выбрал Unity для IOC, когда создавал проект, но я предположил, может быть, неправильно, что IContainerRegistry скрывал клиентов от фактической реализации.Если я обновлю конструктор ViewModel, чтобы получить объект IUnityContainer, он разрешается правильно.

public MainWindowViewModel(IRegionManager aRegionManager,
                           IUnityContainer aContainerProvider) : base()

Это желаемое поведение?

1 Ответ

0 голосов
/ 19 октября 2018

Не делай этого.Вы не хотите, чтобы контейнер находился за пределами вашего корневого разрешения, это ужасно для тестирования, скрывает очевидные иные зависимости и не приносит никакой пользы.

Если вам нужны службы, добавьте их напрямую.Если вам нужны фабрики, введите Func<IProduct> или IHandcraftedFactory.Если вам нужны все зарегистрированные типы, которые реализуют ISomething, введите ISomething[] или IEnumerable<ISomething>.

Пример (комплекс) фабрики с продуктом:

public interface IFactory
{
     IProduct CreateProduct( int someParameter );
}

internal class DeviceFactory : IFactory
{
     public DeviceFactory( IService service )
     {
         _service = service;
     }

     public IProduct CreateProduct( int someParameter ) => new Device( someParameter, _someService );

     private readonly IService _service;
     private class Device : IProduct
     {
         public Device( int someParameter, IService aDependency )
         {
             // ...
         }
     }
}

Если Device не былоесли у вас есть someParameter, вы пропустите IFactory и DeviceFactory и просто введете Func<IProduct> ... единицы, заботясь о том, чтобы каждый Device затем получил IService.

Помните -Контейнер предназначен для упрощения вещей: он разрешает зависимости и создает экземпляры и управляет синглетонами.Но если бы у вас не было контейнера, все бы работало нормально, как в случае с вашими юнит-тестами.Вам просто нужно создать все зависимости вручную.

Вернуться к текущей теме - IContainerRegistry - это просто недолговечная, тонкая оболочка для IUnityContainer (в вашем случае), так что регистрациякод выглядит примерно одинаково в разных приложениях, использующих разные контейнеры.Prism пытается подтолкнуть вас в правильном направлении (см. Выше) с помощью , а не , регистрируя IContainerRegistry так, чтобы вы использовали его там, где вы должны его использовать (во время инициализации модуля), и не позволяет использовать егов другом месте (делая невозможным вводить его).

...