作用
此接口的主要用途是釋放非托管資源。 當不再使用托管對象時,垃圾回收器會自動釋放分配給該對象的內存。 但無法預測進行垃圾回收的時間。 另外,垃圾回收器對窗口句柄或打開的文件和流等非托管資源一無所知。
檢查
在 Visual Studio 中運行代碼分析的時候,如果某一個類中,包含了實現 IDisposable 模式的屬性,則會提醒你該類同樣需要實現 IDisposable 模式,而實現 IDisposable 模式是有一套固定的模式的。這種模式能更有效的防止內存泄漏,也能在某些地方更簡潔的書寫代碼,比如 using 關鍵字就是專為此而生。
using 關鍵字
提供能確保正確使用 IDisposable 對象的方便語法。以下是示例:
using (Font font = new Font("Arial", 10.0f)) {
byte charset = font.GdiCharSet;
}
using 關鍵字保證在離開 using 作用域的時候一定會調用 font.Dispose
。所以,如果只是在局部使用了 IDisposable 變量,最好這樣包起來,以防止內存泄漏。
實現 IDisposable
MSDN 提供了一套標准的實現模板,地址在這:CA1063: Implement IDisposable correctly,我稍微有一點修改的實現了自己的:
/// <summary>
/// @author Easily
/// </summary>
public class BaseObject : IDisposable {
private bool _enabled = true;
public bool enabled {
get { return _enabled; }
}
public void Dispose() {
if (_enabled) {
Dispose(true);
}
}
private void Dispose(bool value) {
if (_enabled) {
_enabled = false;
Destroy();
if (value) {
GC.SuppressFinalize(this);
}
}
}
virtual protected void Destroy() {
// release managed resource here
}
~BaseObject() {
Dispose(false);
}
}
需要釋放的資源會在 Destroy
里面得到釋放,所以,子類如果有需要釋放的資源,必須重寫 Destroy
。Destroy
只會被調用一次,之后 enabled
屬性會被設置為 false
,如果子類在運行過程中正在調用異步的方法,回調必須檢查 enabled
屬性。
並發版本實現
以上的實現在並發環境下很容易出問題,並發的情況下,需要對 _enabled 鎖定,使用 lock
關鍵字即可:
lock (_lockObj) {
_enabled = false;
}
所以,這就需要所有用到 _enabled
的地方都進行鎖定,還有一個方法,使用 Interlocked
提供的原子操作,以下是並發版本:
/// <summary>
/// @author Easily
/// </summary>
public class BaseObject : IDisposable {
private int _disposed;
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing) {
if (Interlocked.CompareExchange(ref _disposed, 1, 0) != 0) {
return;
}
if (disposing) {
Destroy();
}
}
virtual protected void Destroy() {
//
}
~BaseObject() {
Dispose(false);
}
}