在我的 Prism 应用程序中,MEF 容器可通过 Container 属性从 Bootstrapper 类中获得。
但它不是来自类模块(IModule)。我只能通过 IServiceLocator 导入容器。
为什么?我认为针对具体技术使用通用接口是有意义的,但 Prism 4.1 指南要求我们不要使用 IServiceLocator(在使用 IServiceLocator 的注意事项中)。
在我的 Prism 应用程序中,MEF 容器可通过 Container 属性从 Bootstrapper 类中获得。
但它不是来自类模块(IModule)。我只能通过 IServiceLocator 导入容器。
为什么?我认为针对具体技术使用通用接口是有意义的,但 Prism 4.1 指南要求我们不要使用 IServiceLocator(在使用 IServiceLocator 的注意事项中)。
我认为它不对应于 Prism 或 MEF,而是对应于依赖注入原则和一般的最佳实践。(是的,我认为 MEF 不是 DI 容器,但在这里它几乎用作 DI 容器,所以我想在这里使用相同的做法)。
在 DI 的最佳实践中(这本书很酷,我强烈推荐它)在 DI“工作流程”中有这样的步骤是很好的:
理想情况下,您不应再使用 DI 容器。你的代码不应该知道 DI 容器的存在(从这方面来说 Unity 是真正的 DI 容器,因为你可以编写不知道使用 DI 容器的代码)。如果您的代码知道它 - 它取决于 DI 容器,这是一件坏事。
PS。如果你想在你的模块中使用 MEF 容器(例如,因为你对 DI 范式不是很熟悉,或者你有一些非常具体的任务),你可以尝试这样的事情:
[ModuleExport(typeof(YourModule))]
public class YourModule : IModule
{
public static CompositionContainer CompositionContainer;
[ImportingConstructor]
public void YourModule(CompositionContainer container)
{
this.CompositionContainer = container;
}
}
不要忘记在 Boostrapper 中注册 MEF 容器本身:
public class YourBootstrapper: MefBootstrapper
{
protected override CompositionContainer CreateContainer()
{
var container = base.CreateContainer();
container.ComposeExportedValue(container);
return container;
}
}
请注意,我使用的是旧版本的 Prism,并且我将它与 UnityContainer 一起使用,但同样的原则应该适用。
定义您的 Module 类以在构造函数中获取一个容器。
以下是使用 Unity 的示例:
public class Module : IModule
{
public static IUnityContainer Container;
public Module(IUnityContainer container)
{
Container = container;
}
}
如果您定义一个带有容器的构造函数,它将被 ApplicationBootstrapper.Run() 方法调用。
我测试了一个默认的无参数构造函数和一个重载构造函数,它接受容器并调用了第二个构造函数。
我还检查了只有默认构造函数,它被调用了。我建议您更改构造函数以添加带有容器的参数。
在模块类中拥有一个容器将允许您在 Initialize 方法中注册类型。
至于 ServiceLocator,这是一种稍微不同的模式,我建议您在由于某种原因无法让容器创建依赖项的情况下使用它。