【问题标题】:How destroy objects created with MEF如何销毁使用 MEF 创建的对象
【发布时间】:2011-06-02 13:11:47
【问题描述】:

您好,我在 WPF 应用程序中使用 MEF 和 caliburn.micro。我想知道如何销毁使用 MEF 创建的实例。

例如简单的shell:

 [Export(typeof(IShellViewModel))]
    public class ShellViewModel : Conductor<IScreen>.Collection.OneActive, IShellViewModel
    {

        protected override void OnInitialize()
        {
            ShowLogOn();
            base.OnInitialize();
        }

        //first screen
        public void ShowLogOn()
        {
            var vm = IoC.Get<ILogOnViewModel>();
            ActivateItem(vm);
        }

        //second screen
        public void ShowMessenger(Account account)
        {
            ActiveItem.Deactivate(true);
            var vm = IoC.Get<IMessengerViewModel>();
            vm.Account = account;
            ActivateItem(vm);
        }

  }

首屏

[Export(typeof(ILogOnViewModel))]
public class LogOnViewModel : Screen,ILogOnViewModel
{
   User user=new User();
}

第二屏:

  [Export(typeof(IMessengerViewModel))]
            public class MessengerViewModel : Screen, IViewModelIdentity,
                IMessengerViewModel, IHandle<Rp>, IHandle<string>
            {..}

WPF 应用程序从与 ILogOnViewModel 接口关联的第一个屏幕开始。然后我停用此屏幕并激活与 IMessengerViewModel 接口关联的第二个屏幕。

我使用 ANTS 内存分析器检查内存使用情况,但 ILogOnViewModel 的实例仍然存在,用户类的实例也存在。

我是 IoC 的新手,DI...所有使用 MEF 导出的类都必须存在于整个 WPF 应用程序生命周期中?

其他示例,我使用窗口管理器创建新的 wpf 窗口。

[Export(typeof(IChatViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ChatViewModel : Screen, IViewModelIdentity, 
    IChatViewModel, IHandle<Rp>, IHandle<DetailData>
{}

ChatViewModel 是 WPF 窗口。

创建 IChatViewModel 实例:

private IWindowManager _windowManager;
var chatScreen = IoC.Get<IChatViewModel>();
_windowManager.Show(chatScreen);

然后我关闭(单击窗口上的 X(关闭)按钮)WPF 窗口,ChatViewModel 被停用 但是这个类的实例仍然存在。

存在方式如何杀死/销毁这个实例?

【问题讨论】:

    标签: ioc-container mef caliburn.micro memory-management


    【解决方案1】:

    MEF 容器负责管理导出的生命周期,因此无论使用哪个CreationPolicy(默认为Shared),对容器的Dispose 方法的最终调用都会处理任何Export实例(包装您的实际类实例)。此外,在 Export 实例上调用 Dispose 也会导致实际的类实例也被释放。

    要记住的是,GC 正在查看对象图并确定是否有 0 个或多个对该特定实例的引用,因为引用由 MEF CompositionContainer 维护(包装在 Export ) 它不会丢弃该物品。

    如果您强制在您的插件中实现 IDisposable,例如

    public interface ILogOnViewModel : IDisposable { }
    

    并确保在实现 dispose 模式时,允许多次调用它:

    public void Dispose(bool disposing)
    {
        if (disposing && !disposed)
        {
            // Clean up?
        }
    }
    
    public void Dispose()
    {
        Dispose(true);
        GC.SurpressFinalize(this);
    }
    

    然后,您可以安全地在您的 ILogOnViewModel 实现实例上调用 Dispose,而不会在实际容器处理时造成问题。

    【讨论】:

    • 是的,但是在容器被释放之前,对象永远不会被释放,这是一个很大的限制。