14

我在 MEF 的部分生命周期中遇到了一些问题,这会导致我的 Prism 应用程序中的内存泄漏。

我的应用程序导出视图和视图模型并PartCreationPolicy设置为CreationPolicy.NonShared. 视图和视图模型分别继承自ViewBaseViewModelBase,它们实现了IDisposable.

现在,由于我的部件实现IDisposable了,对它们的引用由容器保存,这导致它们不会被垃圾收集器释放。根据零件寿命的 MEF 文档,这是设计使然:

除非满足以下条件之一,否则容器不会保存对其创建的部件的引用:

  • 该部分标记为Shared
  • 该部分实现IDisposable
  • 一个或多个导入配置为允许重组

那么我怎样才能让 MEF 不保留对这些部分的引用呢?是否有一个属性可以让 MEF 知道我不希望它保留对我的部分的引用,即使它实现了IDisposable

上述文章中讨论的两种策略对我来说似乎都不是好的解决方案:

  • ReleaseExport需要一个Export对象作为参数,我不知道如何提供。我有我的视图实例,但我无法知道用于创建视图的合同是什么。如果有一个ReleaseExport可以接收容器创建的任何对象的重载,那就太好了。
  • 使用子容器似乎也不是一个自然的选择。

任何帮助将不胜感激。

4

4 回答 4

8

除非 Prism 支持视图对象的某种生命周期,否则这里没有解决方案,除了IDisposable从视图公开的接口列表中删除。

有三种 MEF 方法来处理这个问题,其他响应者都提到了:

  • ExportFactory<T>
  • 子容器
  • ReleaseExport()

所有这些都需要对请求原始导出的代码部分进行一些工作 - 在这种情况下是 Prism 中的代码。这是有道理的,因为不希望使用对象的代码必须知道它是如何以及何时创建的。

MEF中没有ReleaseExportedObject(),因为多个(例如属性)导出可以返回相同的值;在逻辑上可能提供,但增加的复杂性使其不太可能在可预见的未来由 MEF 解决。

希望这可以帮助; 我已将这个问题重新标记为“棱镜”,因为我确信 Prism 社区中的其他人会遇到这个问题并能够提供建议。

于 2012-01-09T18:52:12.280 回答
5

当您实现时,IDisposable您有点说应该以确定的方式清理类型(IDisposable.Dispose当垃圾收集器决定是时候调用而不是随机调用。

在您的情况下,视图模型只会在您处置可能不是您想要做的容器时处置。为了解决这个问题,我看到了两种可能的解决方案:

  • 不要IDisposable在您的视图模型上实现。显然你不在乎它们什么时候被清理干净,那么为什么要制造它们IDisposable呢?

  • 您可以使用共享视图模型工厂类,而不是让容器创建每个非共享视图模型。然后,您可以将该类注入到视图模型的所有者中,以允许所有者显式地创建视图模型。大概这些所有者也知道何时处置视图模型。

基本上,如果某些东西是一次性的,那也应该是代码中的一个明智点,您需要在其中处理一次性的东西。

于 2012-01-09T13:53:38.687 回答
4

您应该通过导入的ExportFactory<T>创建这些实例。然后,您将拥有必要的控制权以通过 处理它们ExportLifetimeContext<T>.Dispose()

但是,这仅在下一个 .NET 版本 (4.5) 或 codeplex 上的最新 MEF 预览版本中可用。(在旧版本的 MEF 中,相同的功能被实现为示例,并被称为PartCreator,如本文所述。)

于 2012-01-09T13:57:59.987 回答
2

所有其他答案都提供了规避这个问题的好方法,但我最终做的是使用我自己的自定义界面,ICleanup而不是IDisposable. 当然,这可能并不适合所有人。

于 2014-01-06T10:49:42.967 回答