如何正确实现IDisposable接口

   如果一个对象拥有非托管资源,则应该实现IDisposable接口,这样调用方可以在使用之后及时释放资源。
   有很多关于.Net的书籍和文章都描述了如何实现IDisposable接口,但是几乎每一篇实现的都不完全一样,这里将几个主要的实现进行合并,试图找出能够适应绝大多数条件的实现方法。
   
   实现代码
   
 1namespace Disposable
 2{
 3    public class ResourceBase:IDisposable
 4    {
 5        private bool disposed = false;
 6
 7        ~ResourceBase()
 8        {
 9            Dispose(false);
10        }

11
12        protected virtual void Dispose(bool disposing)
13        {
14            if (disposed)
15                return;
16            //多线程环境
17            lock (this)
18            {
19                if (disposing)
20                {
21                    //release managed resource
22                }

23                //release unmanaged resource;
24                disposed = true;
25            }

26        }

27        public void Close()
28        {
29            Dispose();
30        }

31
32        IDisposable Members
41    }

42public class Resource:ResourceBase
43    {
44        private bool disposed = false;
45        protected override void Dispose(bool disposing)
46        {
47            if (disposed)
48                return;
49            //多线程环境
50            lock (this)
51            {
52                try
53                {
54                    if (disposing)
55                    {
56                        //release managed resource
57                    }

58                    //release unmanaged resource
59                    
60                }

61                finally
62                {
63                    base.Dispose(disposing);
64                    disposed = true;
65                }

66
67            }

68            
69        }

70    }

71}
   
   分析
   Dispose()方法用于显式的释放资源,可以在代码中直接调用,或者使用using语句间接调用。GC.SuppressFinalize告诉GC在垃圾回收时,不需要调用析构函数,可以提高垃圾回收的效率。
   Close()方法与Dispose()作用相同,只是为了适应某些有Open方法的类,Open/Close相互对应比较符合一般习惯。
   析构函数用于在垃圾回收的时候释放资源。如果用户没有/忘记在使用之后释放资源,CLR会在垃圾回收的时候调用此函数。虽然资源较晚被释放,但总是好于不释放。
   Dispose(bool)是真正释放资源的地方,参数disposing表明是用户主动释放资源还是在垃圾回收时释放。当用户主动释放资源时,由于此对象的成员中,某些托管资源持有非托管资源,因此需要释放这些托管资源,如果这些托管资源实现了IDisposable,调用Dispose()即可。在垃圾回收时,由于无法确定这些托管资源是否已经被回收了,因此不要试图释放托管资源,GC会释放这些资源的。如果多次调用Dispose(bool)会有副作用,则需要添加disposed变量来判断是否已经释放了资源。如果对象可能会在多线程环境中使用,需要加锁防止同步问题。
   最后,如果该类有派生类的话,要在派生类中override父类的Dispose(bool)方法,并在释放资源后调用父类的Dispose(bool),以正确释放父类的资源。
posted @ 2007-04-17 16:44  Nick Wang (懒人王)  阅读(1381)  评论(2)    收藏  举报