MEF ExportFactory<T> - How to properly dispose in a long-running application?
Basically, is there an easy way to dispose of the imports that are created by an ExportFactory<T>
? The reason I ask is because the exports usually contain a reference to something that is still around, such as the EventAggregator. I don't want to run into the issue where I'm creating hundreds of these 开发者_JAVA技巧and leaving them laying around when they are not necessary.
I noticed that when I create the objects I get back a ExportLifetimeContext<T>
which carries a Dispose with it. But, I don't want to pass back an ExportLifetimeContext
to my ViewModels requesting copies of the ViewModel, hence I pass back the Value. (return Factory.Single(v => v.Metadata.Name.Equals(name)).CreateExport().Value;
)
When you call Dispose
on an ExportLifetimeContext<T>
it will call dispose on any NonShared
part involved in the creation of T
. It won't dispose of any Shared
components. This is a safe behaviour, because if the NonShared
parts were instantiated purely to satisfy the imports for T
, then they can safely be disposed as they won't be used by any other imports.
The only other way I think you could achieve it, would be to customise the Dispose
method to chain the dispose call to any other member properties you import with, e.g.:
[Export(typeof(IFoo))]
public class Foo : IFoo, IDisposable
{
[Import]
public IBar Bar { get; set; }
public void Dispose()
{
var barDisposable = Bar as IDisposable;
if (barDisposable != null)
barDisposable.Dispose();
}
}
But as your type has no visibility of whether the imported instance of IBar
is Shared
or NonShared
you run the risk of disposing of shared components.
I think hanging onto the instance of ExportedLifetimeContext<T>
is the only safe way of achieving what you want.
Not sure if this helps, feels like unnecessary wrapping, but could you possibly:
public class ExportWrapper<T> : IDisposable
{
private readonly ExportLifetimeContext<T> context;
public ExportWrapper<T>(ExportLifetimeContext<T> context)
{
this.context = context;
}
public T Value
{
get { return context.Value; }
}
public void Dispose()
{
context.Dispose();
}
public static implicit operator T(ExportWrapper<T> wrapper)
{
return wrapper.Value;
}
public static implicit operator ExportWrapper<T>(ExportLifetimeContext<T> context)
{
return new ExportWrapper<T>(context);
}
}
Which you could possibly:
[Import(typeof(IBar))]
public ExportFactory<IBar> BarFactory { get; set; }
public void DoSomethingWithBar()
{
using (ExportWrapper<IBar> wrapper = BarFactory.CreateExport())
{
IBar value = wrapper;
// Do something with IBar;
// IBar and NonShared imports will be disposed of after this call finishes.
}
}
Feels a bit dirty...
精彩评论