实现IDisposable接口,手动完成资源回收

之前nc楼猪一直想当然地认为一个对象实现了IDisposable接口,执行GC.Collect方法后,GC会帮助我们自动实现对所有资源的回收。比如下面的一段代码:
1、一个继承自IDisposable接口的类

代码
using  System;
using  System.IO;

class  Sample4GC : IDisposable
{
    
private   string  filePath  =   string .Empty;

    
private  FileStream fs;

    
public  Sample4GC()
    {
        filePath 
=  Path.Combine(AppDomain.CurrentDomain.BaseDirectory,  " test.txt " );
        fs 
=  File.Open(filePath, FileMode.OpenOrCreate);
        
// using (fs = File.Open(filePath, FileMode.OpenOrCreate))  // 没有这么写是因为楼猪以为GC强制回收就可以了
        
// {
        Console.WriteLine( " 打开文本了... " );
        
// }
    }

    
///   <summary>
    
///  Finalize 析构函数
    
///   </summary>
     ~ Sample4GC()
    {
        Console.WriteLine(
" 对象被销毁... " );
    }

    
public   void  Dispose()
    {
        GC.Collect();
// 强制回收
    }
}

 2、测试代码

代码
         static   void  Main( string [] args)
        {
      
            
using  (Sample4GC sample1  =   new  Sample4GC())
            {
                 // code to do
            }

            
// 抛出IOException,提示test.txt正由另一进程使用
             using  (Sample4GC sample2  =   new  Sample4GC())
            {
                 // code to do
            }

            Console.ReadKey();
        }

如您所看到的那样,nc楼猪自以为通过using这种写法,就可以高枕无忧地多次实例化对象了。可是,在sample2实例化执行到构造函数的下面这行:
 fs = File.Open(filePath, FileMode.OpenOrCreate);
竟然抛出了文件被另一个进程使用无法访问的异常。
非常奇怪,难道using了之后,sample1还在占用测试文本资源而没有被回收?可是楼猪在Dispose方法上加了断点,GC.Collect()方法明显执行了一次啊,强制回收了怎么文本资源还被另一个进程使用呢?
无奈,稍微改了一下构造函数里的代码,如下:

代码
   public  Sample4GC()
    {
        filePath 
=  Path.Combine(AppDomain.CurrentDomain.BaseDirectory,  " test.txt " );
        
// fs = File.Open(filePath, FileMode.OpenOrCreate);
         using  (fs  =  File.Open(filePath, FileMode.OpenOrCreate))  // 这样就安全了
        {
            Console.WriteLine(
" 打开文本了... " );
        }
    }

果然这次就没有异常了。可是像上面那样写还要继承IDisposable接口干什么呢? 嗯...难道是Dispose方法里的GC.Collect这玩意没有回收文件流对象么?
好吧,那就把  using (fs = File.Open(filePath, FileMode.OpenOrCreate)) 这种写法再改回原来的 fs = File.Open(filePath, FileMode.OpenOrCreate) 这种不安全的写法,然后再改进Dispose方法试试看:

代码
    public   void  Dispose()
    {
        
if  (fs  !=   null )
        {
            
// fs.Close(); // 关闭 
            fs.Dispose(); // 文件流回收 不管Close还是Dispose 都实现了回收
        }
        GC.Collect();
// 强制回收
    }

我kao,果然正常,而且不管是执行文件流的Close还是Dispose方法,都实现了资源的回收,楼猪不禁一阵激动。

到这里,楼猪可以确定,果然是楼猪自己误解了GC.Collect方法,没有正确实现好Dispose方法。最后模仿msdn优雅的写法,改进一下实现代码:

代码
  class  Sample4GC : IDisposable
    {
        
private   bool  isDisposed  =   false ;

        
private   string  filePath  =   string .Empty;

        
private  FileStream fs;

        
public  Sample4GC()
        {
            filePath 
=  Path.Combine(AppDomain.CurrentDomain.BaseDirectory,  " test.txt " );
            fs 
=  File.Open(filePath, FileMode.OpenOrCreate);
            
// using (fs = File.Open(filePath, FileMode.OpenOrCreate))
            
// {
            Console.WriteLine( " 打开文本了... " );
            
// }
        }

        
///   <summary>
        
///  Finalize 析构函数
        
///   </summary>
         ~ Sample4GC()
        {
            Console.WriteLine(
" 对象被销毁... " );
            Dispose(
false );
        }

        
public   void  Dispose()
        {
            Console.WriteLine(
" 手动销毁对象... " );
            GC.SuppressFinalize(
this );  // 通知GC:对象已经被销毁过,不用GC处理了
              Dispose( true );
        }

        
///   <summary>
        
///  自己实现的对象回收主方法
        
///   </summary>
        
///   <param name="isDisposing"></param>
         private   void  Dispose( bool  isDisposing)
        {
            
if  ( ! isDisposed)
            {
                
if  (isDisposing)
                {
                    
if  (fs  !=   null ) // 手动销毁FileStream对象
                    {
                        
// fs.Close();
                        fs.Dispose();
                    }
                }
            }
            isDisposed 
=   true ;
        }

    }

在调用的时候,我们可以显式调用Dispose方法或者通过using这种写法自动回收资源:

      Sample4GC sample  =   new  Sample4GC();
      sample.Dispose();
// 对象回收 

      
using  (Sample4GC sample2  =   new  Sample4GC())
      {
            // code to do
      }

 



 

你可能感兴趣的:(OS)