C# 中正確實現 IDisposable 接口


作用

此接口的主要用途是釋放非托管資源。 當不再使用托管對象時,垃圾回收器會自動釋放分配給該對象的內存。 但無法預測進行垃圾回收的時間。 另外,垃圾回收器對窗口句柄或打開的文件和流等非托管資源一無所知。

檢查

在 Visual Studio 中運行代碼分析的時候,如果某一個類中,包含了實現 IDisposable 模式的屬性,則會提醒你該類同樣需要實現 IDisposable 模式,而實現 IDisposable 模式是有一套固定的模式的。這種模式能更有效的防止內存泄漏,也能在某些地方更簡潔的書寫代碼,比如 using 關鍵字就是專為此而生。

using 關鍵字

提供能確保正確使用 IDisposable 對象的方便語法。以下是示例:

 
 
 
         
  1. using (Font font = new Font("Arial", 10.0f)) {
  2. byte charset = font.GdiCharSet;
  3. }

using 關鍵字保證在離開 using 作用域的時候一定會調用 font.Dispose 。所以,如果只是在局部使用了 IDisposable 變量,最好這樣包起來,以防止內存泄漏。

實現 IDisposable

MSDN 提供了一套標准的實現模板,地址在這:CA1063: Implement IDisposable correctly,我稍微有一點修改的實現了自己的:

 
 
 
         
  1. /// <summary>
  2. /// @author Easily
  3. /// </summary>
  4. public class BaseObject : IDisposable {
  5. private bool _enabled = true;
  6. public bool enabled {
  7. get { return _enabled; }
  8. }
  9. public void Dispose() {
  10. if (_enabled) {
  11. Dispose(true);
  12. }
  13. }
  14. private void Dispose(bool value) {
  15. if (_enabled) {
  16. _enabled = false;
  17. Destroy();
  18. if (value) {
  19. GC.SuppressFinalize(this);
  20. }
  21. }
  22. }
  23. virtual protected void Destroy() {
  24. // release managed resource here
  25. }
  26. ~BaseObject() {
  27. Dispose(false);
  28. }
  29. }

需要釋放的資源會在 Destroy 里面得到釋放,所以,子類如果有需要釋放的資源,必須重寫 DestroyDestroy 只會被調用一次,之后 enabled 屬性會被設置為 false,如果子類在運行過程中正在調用異步的方法,回調必須檢查 enabled 屬性。

並發版本實現

以上的實現在並發環境下很容易出問題,並發的情況下,需要對 _enabled 鎖定,使用 lock 關鍵字即可:

 
 
 
         
  1. lock (_lockObj) {
  2. _enabled = false;
  3. }

所以,這就需要所有用到 _enabled 的地方都進行鎖定,還有一個方法,使用 Interlocked 提供的原子操作,以下是並發版本:

 
 
 
         
  1. /// <summary>
  2. /// @author Easily
  3. /// </summary>
  4. public class BaseObject : IDisposable {
  5. private int _disposed;
  6. public void Dispose() {
  7. Dispose(true);
  8. GC.SuppressFinalize(this);
  9. }
  10. private void Dispose(bool disposing) {
  11. if (Interlocked.CompareExchange(ref _disposed, 1, 0) != 0) {
  12. return;
  13. }
  14. if (disposing) {
  15. Destroy();
  16. }
  17. }
  18. virtual protected void Destroy() {
  19. //
  20. }
  21. ~BaseObject() {
  22. Dispose(false);
  23. }
  24. }





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM