[Silverlight入门系列]Prism的ViewModel和Service实现IDisposable接口Unsub

来源:转载

内存泄露的问题 Memory Leak Issue

Prism的ViewModel和Service为避免内存泄露最好实现IDisposable接口来释放非托管资源(Unmanaged Resources),非托管资源一般都是放在栈上,而托管资源都是存储在堆上,例如,一个ViewModel订阅了事件最好在Dispose的时候Unsubscribe事件订阅,用了Timer要释放,用了persistent storage要释放,用了Stream要关闭,打开数据链接要关闭,EventHandler += ... 要有EventHandler -= ....实现 Finalize 和 Dispose 以清理非托管资源是最简洁的方式。但并不是说强制每一个ViewModel必须实现IDisposable接口。为什么不强制?因为如果你的ViewModel和Service没有用到非托管资源而实现了IDisposable接口未必有好处,因为最终的内存释放是有GC来负责的,而GC有一个不可预测性,也就是说GC Heap上的对象生存期完全看GC是否要回收它而决定。好的,回到正题,这里举例一个ViewModel实现IDisposable接口的源码:

#region IDisposable
public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
    if (!disposing) return;

    //取消订阅事件,注意事件订阅的KeepAlive = false
    TheEventAggregator.GetEvent<MyEvent>().Unsubscribe(MyDeleteagetMethod);

    //释放Timer
    if (_timer != null)
        _timer.Dispose();
    _timer = null;
}

// Use C# destructor syntax for finalization code.
~MarketFeedService()
{
    Dispose(false);
}

#endregion

MVVMLight的ICleanup接口

MVVMLight的ICleanup接口并不是要取代IDisposable接口,据MVVMLight的作者说,他用这个接口的目的是提供一个一致的接口和方式来清理和释放资源,例如一个实现了ICleanup接口的View的DataContext是一个实现了ICleanup接口的ViewModel,就可以手动调用ICleanup接口来释放其ViewModel的资源,此外,还可以通过ViewModelLocator.Cleanup()来释放所有ViewModel的资源。来看一个实现了ICleanup接口的View的ICleanup实现:

#region "ICleanup interface implementation"

 public void Cleanup()
 {
     // call Cleanup on its ViewModel
     ((ICleanup)this.DataContext).Cleanup();
     
     // call Cleanup on IssueEditor
     ICleanup issueEditor = this.issueEditorContentControl.Content as ICleanup;
     if (issueEditor != null)
         issueEditor.Cleanup();
     this.issueEditorContentControl.Content = null;
     
     // cleanup itself
     Messenger.Default.Unregister(this);
     
     // set DataContext to null and call ReleaseExport()
     this.DataContext = null;
     
     //Release export
     App.Container.ReleaseExport<ViewModelBase>(_viewModelExport);
     
     _viewModelExport = null;
 }

 #endregion "ICleanup interface implementation"

IDisposable单元测试Unit Testing IDisposable

如何确定你的IDisposable接口正确实现了呢?最好写个单元测试,像这样:

[TestMethod()]
public void TestDisposeConstructorTest()
{
    TestDispose target = new TestDispose();//TestDispose是我们要测试的类
    target.Dispose();

    //用下面的代码来调用Finalizer
    //System.GC.Collect();
    //因为GC.Collect是异步的,用下面的代码来同步等待Finalize
    //System.GC.WaitForPendingFinalizers();

    Assert.IsNull(target);//target is NOT null 因为Finalize认为target还存在引用, but target._timer = null
}

注意测试会失败,target is NOT null 因为Finalize认为target还存在引用, but target._timer = null。

有关IDisposable接口的最佳实践请参考这篇文章。

本文来自Mainz的博客,原文地址:http://www.cnblogs.com/Mainz/archive/2011/06/30/2094691.html


分享给朋友:
您可能感兴趣的文章:
随机阅读: