首页 文章

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

提问于
浏览
1

我最近有机会创建一个新的基于棱镜的应用程序 . 我已经使用6.3版本了很长一段时间,但看到棱镜7已经退出预发行版并且想尝试一下 . 我使用棱镜模板包创建了一个新的棱镜应用程序,并且所有工作都按预期开箱即用 . 我更新了视图模型,就像通常在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版本做错了什么?

EDIT: Per @mnistic

以下是传递IContainerRegistry的App.xaml.cs提供的模板包中的代码 .

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

Update

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

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

这是理想的行为吗?

1 回答

  • 1

    不要这样做 . 你不希望容器在你的分辨率根之外,测试是可怕的,隐藏其他显而易见的依赖关系,并没有任何好处 .

    如果您需要服务,请直接注入 . 如果您需要工厂,请注入 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 来推动你朝着正确的方向前进(见上文),以便你在你应该使用它的地方使用它(在模块初始化期间)并阻止你在别处使用它(通过使它无法注入它) .

相关问题