Prism 7 - 将 IContainer 对象注入视图模型
Prism 7 - Injecting the IContainer objects into a view model
我最近有机会创建一个新的基于棱镜的应用程序。我已经使用 6.3 版本有一段时间了,但看到 prism 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 版本做错了什么吗?
编辑:根据@mnistic
这是提供的模板包中的代码 App.xaml.cs,其中传入了 IContainerRegistry。
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
//containerRegistry is a valid instance here
}
更新:
再深入一点,传递给 RegisterTypes 的 IContainerRegistry 列出了调用该方法时可用的所有 types/interfaces。它注册了一个 IUnityContainer 实例。我在创建项目时为 IOC 选择了 Unity,但我假设 IContainerRegistry 隐藏了实际实现中的客户端,这可能是错误的。如果我更新 ViewModel 构造函数以接收 IUnityContainer 的对象,它会正确解析。
public MainWindowViewModel(IRegionManager aRegionManager,
IUnityContainer aContainerProvider) : base()
这是期望的行为吗?
不要这样做。你不希望容器位于你的解析根目录之外,测试起来很糟糕,隐藏了其他明显的依赖关系并且没有任何好处。
如果需要服务,直接注入。如果您需要工厂,请注入 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>
... Unity 负责然后每个 Device
收到它的 IService
。
记住 - 容器的存在是为了简化事情:它解决依赖关系并创建实例并管理单例。但是如果你没有容器,一切仍然会正常工作,就像你的单元测试一样。您只需手动创建所有依赖项。
回到手头的主题 - IContainerRegistry
只是 IUnityContainer
(在你的情况下)的短暂的薄包装,因此注册码在不同的应用程序中看起来有些相似使用不同的容器。 Prism 试图通过 not 注册 IContainerRegistry
将您推向正确的方向(见上文),以便您在应该使用它的地方使用它(在模块初始化期间)并阻止您在其他地方使用它(通过使其无法注入)。
我最近有机会创建一个新的基于棱镜的应用程序。我已经使用 6.3 版本有一段时间了,但看到 prism 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 版本做错了什么吗?
编辑:根据@mnistic
这是提供的模板包中的代码 App.xaml.cs,其中传入了 IContainerRegistry。
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
//containerRegistry is a valid instance here
}
更新:
再深入一点,传递给 RegisterTypes 的 IContainerRegistry 列出了调用该方法时可用的所有 types/interfaces。它注册了一个 IUnityContainer 实例。我在创建项目时为 IOC 选择了 Unity,但我假设 IContainerRegistry 隐藏了实际实现中的客户端,这可能是错误的。如果我更新 ViewModel 构造函数以接收 IUnityContainer 的对象,它会正确解析。
public MainWindowViewModel(IRegionManager aRegionManager,
IUnityContainer aContainerProvider) : base()
这是期望的行为吗?
不要这样做。你不希望容器位于你的解析根目录之外,测试起来很糟糕,隐藏了其他明显的依赖关系并且没有任何好处。
如果需要服务,直接注入。如果您需要工厂,请注入 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>
... Unity 负责然后每个 Device
收到它的 IService
。
记住 - 容器的存在是为了简化事情:它解决依赖关系并创建实例并管理单例。但是如果你没有容器,一切仍然会正常工作,就像你的单元测试一样。您只需手动创建所有依赖项。
回到手头的主题 - IContainerRegistry
只是 IUnityContainer
(在你的情况下)的短暂的薄包装,因此注册码在不同的应用程序中看起来有些相似使用不同的容器。 Prism 试图通过 not 注册 IContainerRegistry
将您推向正确的方向(见上文),以便您在应该使用它的地方使用它(在模块初始化期间)并阻止您在其他地方使用它(通过使其无法注入)。