我在MEF的部件生命周期中遇到了一些问题,导致我的Prism应用程序中出现内存泄漏。
我的应用程序导出视图和视图模型,PartCreationPolicy
设置为CreationPolicy.NonShared
。视图和视图模型分别从ViewBase
和ViewModelBase
继承,实现IDisposable
。
现在,由于我的部件实现了IDisposable
,因此容器会保留对它们的引用,这会导致它们不被垃圾收集器释放。根据{{3}},这是设计的:
除非满足下列条件之一,否则容器将不会保留对其创建的零件的引用:
- 该部分标记为
Shared
- 该部分实现了
IDisposable
- 配置一个或多个导入以允许重新组合
那么我怎样才能让MEF不参考这些部分?是否有一个属性可以让MEF知道我不希望它保留对我的部分的引用,即使它实现了IDisposable
?
上述文章中讨论的两种策略对我来说似乎都不是很好的解决方案:
ReleaseExport
需要Export
个对象作为参数,我不知道如何提供。我有我的观点的实例,但是我无法知道用于创建视图的合同是什么。如果ReleaseExport
的重载可以接收容器创建的任何对象,那将会很棒。非常感谢任何帮助。
答案 0 :(得分:7)
除非Prism支持视图对象的某种生命周期,否则除了从视图公开的接口列表中删除IDisposable
之外,这里没有解决方案。
有三种MEF方法可以解决这个问题,其他响应者都提到了这些方法:
ExportFactory<T>
ReleaseExport()
所有这些都需要在请求原始导出的代码方面做一些工作 - 在这种情况下是Prism中的代码。这是有道理的,因为消费对象的代码不得不知道它是如何以及何时被创建的。
MEF中没有ReleaseExportedObject()
,因为多个(例如属性)导出可以返回相同的值;它在逻辑上可能提供,但增加的复杂性使MEF在可预见的未来不太可能解决。
希望这会有所帮助;我已经重新提出这个问题'棱镜',因为我相信Prism社区的其他人会遇到这个并能够提供建议。
答案 1 :(得分:5)
当你实现IDisposable
时,你有点说应该以确定的方式清理类型(通过调用IDisposable.Dispose
而不是当垃圾收集器确定它是时间时随机清理。
在您的情况下,视图模型将仅在您处置可能不是您想要的容器时处理。为了解决这个问题,我看到了两种可能的解决方案:
请勿在视图模型上实施IDisposable
。显然你不关心他们什么时候被清理,为什么要让他们IDisposable
?
您可以使用共享视图模型工厂类,而不是让容器创建非共享的每个视图模型。然后,您可以将该类注入视图模型的所有者,以允许所有者明确创建视图模型。假设这些所有者也知道何时处置视图模型。
基本上,如果某些东西是一次性的,那么在您需要处理可丢弃的代码时,代码中也应该是一个明智的点。
答案 2 :(得分:4)
您应该通过导入的ExportFactory<T>创建这些实例。然后,您将获得必要的控制权,以通过ExportLifetimeContext<T>.Dispose()
处理它们。
但是,这只能在下一个.NET版本(4.5)或在codeplex上的最新MEF预览版本中开箱即用。 (在旧版本的MEF中,相同的功能作为样本实现,并被称为 PartCreator ,如此blog post中所述。)
答案 3 :(得分:2)
所有其他答案提供了绕过这个问题的好方法,但最终我最终做的是使用我自己的自定义界面ICleanup
,而不是IDisposable
。这当然可能并不适合所有人。