Prism 7-将IContainer对象注入视图模型

时间:2018-10-19 18:23:18

标签: mvvm unity-container prism prism-7

我最近有机会创建一个新的基于棱镜的应用程序。我使用6.3版本已经有一段时间了,但是看到Prism 7已经退出预发行版本,想尝试一下。我使用Prism模板包创建了一个新的棱镜应用程序,并且所有功能都能按预期工作。我像在6.3中通常所做的那样更新了视图模型以传递到Container中,因此我可以解析一些对象,以便稍后向视图提供信息,在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版本,我做错什么了吗?

编辑:按@mnistic

这是App.xaml.cs提供的模板包中的代码,其中传递了IContainerRegistry。

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

更新

再深入一点,传递给RegisterTypes的IContainerRegistry列出了在调用该方法时可用的所有类型/接口。它注册了一个IUnityContainer实例。在创建项目时,我为IOC选择了Unity,但我可能会错误地认为IContainerRegistry正在将客户端隐藏在实际的实现中。如果我更新ViewModel构造函数以接受IUnityContainer的对象,它将正确解析。

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

这是理想的行为吗?

1 个答案:

答案 0 :(得分:2)

请勿执行此操作。您不希望将容器放在解决方案的根目录之外,这很可怕,需要进行测试,否则会隐藏明显的依赖关系,并且毫无益处。

如果需要服务,请直接注射。如果需要工厂,请注入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,则跳过IFactoryDeviceFactory,而只注入Func<IProduct> ... Device然后收到其IService

请记住-容器在那里可以简化事情:它可以解决依赖关系,创建实例并管理单例。但是,如果您没有容器,那么一切都会正常进行,就像单元测试中那样。您只需手动创建所有依赖项。

回到当前的主题-IContainerRegistry只是IUnityContainer周围的一个短而薄的包装器(在您的情况下),因此在使用不同应用程序的不同应用程序中,注册码看起来有些相似容器。 Prism尝试通过注册IContainerRegistry来朝着正确的方向(请参见上文)推动您,以便在应该使用它的地方使用它(在模块初始化期间)并防止您避免在其他地方使用它(使其无法注入)。