MEF的对象破坏问题

我使用静态变量来保存对象的数量。 在构造函数中,我增加了这个变量。 这样我知道创建了多少个对象实例。 使用这些对象后,它们会被解除引用。 我怀疑MEF是否持有对这些对象的引用,因此我强制GC进行清理(使用GC.Collect()方法)。 我希望在下一个对象创建时,这个变量从零开始,但它从最后一个数字开始重新开始。 我在destructor放置了一个用于跟踪的日志记录机制,只有在应用程序关闭后才会销毁对象。 我可以假设MEF已经创建了对这些对象的其他引用吗?

我使用MEFExportFactory来创建我的对象

编辑:

也许应该用ExportLifetimeContext做些什么?

我强迫GC进行清理

如果MEF仍然有对象的引用,那么显然这没有做任何事情。 如果对象已经变成垃圾,那么垃圾收集器将自动收集它们 – 要求它明确地执行它只是一个可能被忽略的提示。 无论哪种方式,这都没有必要。

我在析构函数中放置了一个用于跟踪的日志记录机制,只有在应用程序关闭后才会销毁对象。 我可以假设MEF已经创建了对这些对象的其他引用吗?

MEF将保留对已创建对象的引用,以便在您请求导出时能够重复返回相同的引用。 要让MEF放弃这些引用,您应该调用CompositionContainer.Dispose 。 显然,在此之后你不能再重复使用容器,尽管你可以创建一个新容器。

MEF也是它创建的任何IDisposable对象的所有者。 这意味着当您处置容器时,它会在放弃引用之前调用任何此类对象上的Dispose

最好依靠对Dispose调用来执行清理,而不是使用终结器。 无法保证终结器完全运行 。

编辑:

我需要在使用它之后销毁它。 但我不想破坏容器。 我希望MEF作为一个工厂来创建询问部件的新实例,并且调用者应该能够在他不再需要时销毁该对象。 你能帮忙吗?

这就是ExportFactory的用途。 (它以前被称为PartCreator )。 不幸的是,除非您使用Silverlight,否则它在.NET 4中尚不可用。 您可以使用codeplex的预览版本试一试。

如果您不想使用MEF的预览版本,您可以通过创建包装容器的工厂类并使用其GetExportReleaseExport方法来获取和释放对象,从而实现自己的GetExport 。 如果需要创建同一部件的多个实例,请不要忘记设置PartCreationPolicy

编辑2:我错过了你一直在使用ExportFactory 完成对象后,您只需要调用ExportLifeTimeContext.Dispose

CLR中对象的及时“破坏”(即最终确定)不是一件好事。 如果您是出于调试目的而这样做,则没有必要。 您可以按照我对此问题的回答中的说明找出某些类型的对象仍然存在的数量:

C#WPF中的内存泄漏

如果您真的试图让您的软件行为取决于GC未回收的类实例数,那么您需要重新考虑您的设计。 有几种更好的方法可以达到你想要的效果。

对于共享对象,只要容器处于活动状态,MEF就会保留对它们的引用。 您可以在适当的情况下尽早处理非共享部件。 如果您正在使用ExportFactory,则需要处理CreateExport方法返回的ExportLifetimeContext以处置作为请求的一部分创建的任何NonShared部件。 如果在容器上调用了GetExport方法,则可以调用ReleaseExport方法。 如果您以其他方式获得导出(即SatisfyImports或其他),则无法释放它们,因此您可能希望重构您的应用程序以使用ExportFactory或GetExport。

MEF现在有一个支持ExportFactory的桌面版本。 虽然名称有“导出”字样,但您应该在执行“导入”的位置实现它。 调用CreateExport()方法创建零件的新实例将返回一个ExportLifetimeContext此对象具有Dispose()方法,该方法稍后可用于释放导出的对象。 此方法将自动调用您的对象Dispose() ,您无需手动调用它。

这种行为是因为容器本身就是创建对象的所有者,甚至在引用这些对象时调用它们的Dispose()对它们没有影响。