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


    之前一直想当然地认为一个对象实现了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
          }
  • 相关阅读:
    搜索存储过程中的关键字
    替换回车换行
    js 常用正则表达式
    获取存储过程返回值
    DataReader 转datatable
    文件打包下载
    My97DatePicker设置当天之后的日期不可选变灰色
    嵌套类引用实例化的外部类的方法
    可叠加定义的成员变量的赋值及操作(权限)
    Java中List中remove的实质
  • 原文地址:https://www.cnblogs.com/zxktxj/p/2465813.html
Copyright © 2020-2023  润新知