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

摘要:
对象实现IDisposable接口一直是理所当然的。执行GC后。Collect方法,GC将帮助我们自动回收所有资源。这很奇怪。使用后,sample1仍然占用测试文本资源,并且没有被回收?但我为什么要继承IDisposable接口?在这里,卢猪可以肯定,卢猪自己误解了GC。Collect方法,未正确实现Dispose方法。

之前一直想当然地认为一个对象实现了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
      }

免责声明:文章转载自《手动实现IDisposable接口完成资源回收》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇关于Mail协议的SMTP、POP3和IMAPubantu crontab e 无法编辑保存退出的问题下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

Spring通过MimeMessageHelper发送邮件,中文附件名出现乱码解决办法

1.设置系统值system。setProperty(“mail.mime.split-longparameters”,“false”);2.在这里,定义创建对象时的编码格式(utf-8):MimeMessageHelper=newMimeMessageHelper(mes,true,“utf-8”);3.其次,添加附件时,附件名称为helper。需要定义代码...

HTTP请求报文

不仅报表样式可以传递请求参数,请求url也可以以类似于键值对的方式传递数据...

C# winform开发嵌套Chrome内核浏览器(WebKit.net)开发(一)

//Www.cnblogs.com/Maxq/p/6566558.htmlWebKit.net是WebKit的一个net包。使用它,。net程序可以非常方便地集成和使用webkit作为加载网页的容器。EventArgse){WebKit.WebKitBrowser=newWebKitBrowser();this.Controls.Add(浏览器);...

(转)JavaScript-性能优化之函数节流(throttle)与函数去抖(debounce)

简单来说,JavaScript性能优化的函数节流和函数去抖动功能节流就是使函数在极短的时间间隔内无法连续调用。下一个函数调用只能在上次函数执行超过指定的时间间隔后进行。对于这两个需求,有两种解决方案:去抖动和节流。Throwle和debouck是解决请求和响应速度不匹配问题的两种解决方案。抛出以相等的间隔执行函数。如果事件在反跳时间间隔t内再次触发,则将再次...

IntelliJ idea设置显示错误代码提示

idea默认关闭自动编译,所以一些编译错误只有在编译的时候才会提示,例如修改了引用类。按图中设置打开自动编译:注意:idea默认打开省电模式,自动编译在省电模式下被禁用,所以需要在file˃powersavemode关闭省电模式。...

FTPClient

(iReplyCode==331||iReplyCode==230)){CloseSocketConnect();thrownewIOException(strReply.Substring(4));}if(iReplyCode!=230){SendCommand("PASS"+strRemotePass);if(!=null){SendCommand("Q...