Object destruction problem with MEF

2019-02-16 03:41发布

问题:

I use a static variable for holding the count of objects. In constructor I increase this variable. This way I know how many instances of the object are created. After using the objects, they are leaved dereferenced. I'm doubtful if MEF is holding references to these objects so I force GC to do a clean up (Using GC.Collect() method). I expect on next object creation this variable start from zero but it resumes from last number. I put a logging mechanism in destructor for tracing, and objects are destroyed only after the application is closed. Can I assume MEF has created other references to those objects ?

I use MEF and ExportFactory for creating my objects

Edit:

Maybe something with ExportLifetimeContext should be done ?

回答1:

I force GC to do a clean up

If MEF still has references to the objects, then obviously this doesn't do anything. If the objects have become garbage, then the garbage collector will automatically collect them - asking it to do that explicitly is just a hint that might be ignored. Either way, this is not necessary.

I put a logging mechanism in destructor for tracing, and objects are destroyed only after the application is closed. Can I assume MEF has created other references to those objects ?

MEF will hold references to created objects so that it is able to repeatedly return the same reference when you ask for an export. To ask MEF to abandon these references, you should call CompositionContainer.Dispose. Obviously you cannot reuse the container any more after that, though you could create a new one.

MEF is also the owner of any IDisposable objects it creates. This means that when you dispose the container, it will call Dispose on any such objects before abandoning the reference.

It is preferable to rely on calls to Dispose to perform cleanup, rather than to use finalizers. There is no guarantee that finalizers are run at all.

edit:

I need to destroy the object after using it. But I don't want to destroy the container. I want MEF as a factory for creating new instances of asking part, and the caller should be capable of destroying the object when he doesn't need anymore. Can you help with this ?

This is what ExportFactory is for. (It was formerly called PartCreator). Unfortunately it is not yet available in .NET 4, unless you use Silverlight. You can use the preview releases from codeplex to already give it a try.

If you don't want to use the preview releases of MEF, you might be able to implement something like ExportFactory yourself by creating factory classes that wrap the container and by using its GetExport and ReleaseExport methods to acquire and release objects. Don't forget to set a PartCreationPolicy if you need to create multiple instances of the same part.

edit 2: I somehow missed that you were already using ExportFactory all along. You simply need to call ExportLifeTimeContext.Dispose when you're done with the object!



回答2:

The timely "destruction" (that is finalization) of objects in the CLR is not a good thing to rely on. If you're doing this for debugging purposes, there's no need. You can find out how many objects of some type are still in existence by following the instructions in my answer to this question:

Memory Leaks in C# WPF

If you are genuinely trying to make your software's behaviour depend on a count of the number of instances of a class that have not been reclaimed by the GC, then you need to rethink your design. There will be several better ways of achieving what you want.



回答3:

For shared objects, MEF will keep references to them as long as the container is alive. You can have NonShared parts be disposed early in the right circumstances. If you are using ExportFactory, you need to dispose the ExportLifetimeContext returned by the CreateExport method to dispose any NonShared parts created as part of the request. If you called a GetExport method on the container, you can call the ReleaseExport method. If you got the exports some other way (ie SatisfyImports or something), there isn't a way to release them so you may want to refactor your application to use ExportFactory or GetExport.



回答4:

MEF now has a desktop version which supports ExportFactory. Although the name has 'export' word, you should implement it where you are doing your 'imports'. A call to CreateExport() method for creating a new instance of your part will return an ExportLifetimeContext<T> an this object has a Dispose() method which could be used later for releasing exported object. This method would call your object Dispose() automatically and you don't need to call it manually.

This behavior is because the container is the owner of created objects by itself and even with a reference to these objects calling their Dispose() has no effect on them.