CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  .NET技术 >  C#

谁帮我解答一下Dispose、SuppressFinalize、析构函数的概念,联系,区别,执行顺序等等,反正我是挺乱,希望大家帮我理理

楼主fayeflash(我爱阿菲)2005-07-28 13:38:52 在 .NET技术 / C# 提问

谁帮我解答一下Dispose、SuppressFinalize、析构函数的概念,联系,区别,执行顺序等等,反正我是挺乱,希望大家帮我理理,顶者有分 问题点数:100、回复次数:15Top

1 楼lovvver(ElephantTalk.Bright)回复于 2005-07-28 14:08:09 得分 5

我也挺乱的,帮你顶顶吧Top

2 楼JzeroBiao(先知)回复于 2005-07-28 14:34:31 得分 10

Dispose  
  对象不同,Dispose方法也不太一样.  
   
  SuppressFinalize  
  请求系统不要调用指定对象的完成器方法。  
   
  析构函数是自动调用的,它不能被显式调用。当任何代码都不再可能使用一个实例时,该实例就符合被销毁的条件。此后,它所对应的实例析构函数随时均可能被调用。销毁一个实例时,按照从派生程度最大到派生程度最小的顺序,调用该实例的继承链中的各个析构函数。析构函数可以在任何线程上执行Top

3 楼fayeflash(我爱阿菲)回复于 2005-07-28 14:45:28 得分 0

恩!谢谢JzeroBiao(先知)!就需要这样的前辈帮我解答些问题!Top

4 楼xiao_p(kkk)回复于 2005-07-28 15:16:44 得分 5

咔咔  
  还是不明白!!~~Top

5 楼bflovesnow()回复于 2005-07-28 16:25:53 得分 10

1)Finalize   方法的主要用途是确保在对象释放内存时同时清理谇对象所占有的非托管资源。  
  2)在封装了非托管类型,如文件、网络连接、数据库连接等,就必须重写   Finalize   方法,以便让   CLR   在垃圾回收时可以回收这些对象所占有的非托管资源。  
  3)Finalize   是私有方法,它只有在CLR进行垃圾回收时被   CLR   调用,在程序中无法显式调用   Finalize   方法。  
  4)Dispose   是   CLR   提供给开发人员显式释放对象所占有的非托管资源和关闭对象的方法,因为开发人员知道何时不再使用该对象,但并不能释放托管堆中的内存,释放托管堆中的内存仍有CLR在负责。  
  5)SuppressFinalize   是告诉   CLR   先不要释放该对象,以免影响它引用了它的对象发生异常  
  6)一般要析构函数里自动生成调用   Finalize   方法的调用。  
   
   
  以上是个人的理解,请指正!Top

6 楼fayeflash(我爱阿菲)回复于 2005-07-28 17:07:16 得分 0

我现在有一点不明白,那就是为什么有的类偏要实现IDispose接口并实现Dispose的方法,并把释放非托管资源的代码写在里面,然后显式的调用。  
  我这么办不行吗:  
  在类里面写一个共有的方法叫MyMethod,这里面写些释放的代码,因为我自己知道什么时候这个类的实例将不再使用,所以我可以在使用完毕的时候调用MyMethod,然后就不管了,反正非托管的资源我已经释放了,剩下的就是垃圾回收器做的事情了。  
   
  还有呀,我觉得   bflovesnow()   说的很有道理,那么这么做不行吗:  
  我不实现Dispose方法,把所有的非托管资源的释放的代码都写在Finalize的里面,然后就不管了,因为反正垃圾回收器在释放托管资源的同时会调用Finalize方法,也就会释放非托管资源了。  
   
  呵呵,我的想法可能比较的怪,还请大家指教。  
  真心的感谢   bflovesnow()   的解释!Top

7 楼Roaming_Sheep(Roaming Sheep)回复于 2005-07-28 18:59:40 得分 10

我现在有一点不明白,那就是为什么有的类偏要实现IDispose接口并实现Dispose的方法,并把释放非托管资源的代码写在里面,然后显式的调用。  
  我这么办不行吗:  
  在类里面写一个共有的方法叫MyMethod,这里面写些释放的代码,因为我自己知道什么时候这个类的实例将不再使用,所以我可以在使用完毕的时候调用MyMethod,然后就不管了,反正非托管的资源我已经释放了,剩下的就是垃圾回收器做的事情了。  
  ————————————————————————————————————————  
  别人使用这些类的时候,难免会感到困惑、不适  
   
   
   
  还有呀,我觉得   bflovesnow()   说的很有道理,那么这么做不行吗:  
  我不实现Dispose方法,把所有的非托管资源的释放的代码都写在Finalize的里面,然后就不管了,因为反正垃圾回收器在释放托管资源的同时会调用Finalize方法,也就会释放非托管资源了。  
  ————————————————————————————————————————  
  什么时候进行垃圾回收是你不能控制的  
  而很多时候你需要在一个确切的时间就释放掉非托管资源,这样就不能依赖于finalize了,因为你根本不知道什么时候finalize才会被调用Top

8 楼fayeflash(我爱阿菲)回复于 2005-07-28 19:21:57 得分 0

我理解了一下,不知道对不对:  
  1、也就是说,如果用到了非托管资源,那么实现Dispose的方法,在里面去释放非托管的资源是个好习惯,而且,当不再用一个类的实例的时候去调用Dispose方法也是个好习惯。  
  2、把释放非托管资源的代码放到析构函数里和finalize是一样的,因为析构函数也要去调用finalize方法。  
  还有些疑问  
  1、如果我在finalize里没有释放非托管的资源,而且也没有实现Dispose方法,在析构函数里也没有释放非托管资源,是否意味着我犯了个不可弥补的错误,也就是说CLR无能为力了,这部分的资源会失去了?  
  2、如果我在Dispose里释放了资源,并且已经显式的调用,而在析构函数里又去调用Dispose,最后CLR在执行析构函数函数的时候会不会出错?  
   
  看来我的思维是够乱的了,呵呵,谢谢各位的帮忙,谢谢了。Top

9 楼symboltome(符号)回复于 2005-07-29 08:32:37 得分 5

看得我都有点乱了 :)Top

10 楼understand999()回复于 2005-07-29 10:45:41 得分 0

eform自定义表单平台是一个在IE浏览器中可视化的设计软件界面的工具。无论是输入界面还是报表界面,无论是简单的输入查询还是复杂的逻辑处理。都可以由eform设计出来。    
     
            eform自定义表单平台适用于网上OA系统的自定义表单模块,工作流系统的自定义表单模块,信息管理系统方面的软件开发项目等等。    
  Top

11 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2005-07-30 10:11:31 得分 0

1、Finalize方法(C#中是析构函数,以下称析构函数)是用于释放非托管资源的,而托管资源会由GC自动回收。所以,我们也可以这样来区分托管和非托管资源。所有会由GC自动回收的资源,就是托管的资源,而不能由GC自动回收的资源,就是非托管资源。在我们的类中直接使用非托管资源的情况很少,所以基本上不用我们写析构函数。  
   
   
  2、大部分的非托管资源会给系统带来很多负面影响,例如数据库连接不被释放就可能导致连接池中的可用数据库连接用尽。文件不关闭会导致其它进程无法读写这个文件等等。  
   
   
  实现模型:  
  1、由于大多数的非托管资源都要求可以手动释放,所以,我们应该专门为释放非托管资源公开一个方法。实现IDispose接口的Dispose方法是最好的模型,因为C#支持using语句快,可以在离开语句块时自动调用Dispose方法。  
   
  2、虽然可以手动释放非托管资源,我们仍然要在析构函数中释放非托管资源,这样才是安全的应用程序。否则如果因为程序员的疏忽忘记了手动释放非托管资源,那么就会带来灾难性的后果。所以说在析构函数中释放非托管资源,是一种补救的措施,至少对于大多数类来说是如此。  
   
  3、由于析构函数的调用将导致GC对对象回收的效率降低,所以如果已经完成了析构函数该干的事情(例如释放非托管资源),就应当使用SuppressFinalize方法告诉GC不需要再执行某个对象的析构函数。  
   
  4、析构函数中只能释放非托管资源而不能对任何托管的对象/资源进行操作。因为你无法预测析构函数的运行时机,所以,当析构函数被执行的时候,也许你进行操作的托管资源已经被释放了。这样将导致严重的后果。  
   
  5、(这是一个规则)如果一个类拥有一个实现了IDispose接口类型的成员,并创建(注意是创建,而不是接收,必须是由类自己创建)它的实例对象,则这个类也应该实现IDispose接口,并在Dispose方法中调用所有实现了IDispose接口的成员的Dispose方法。  
  只有这样的才能保证所有实现了IDispose接口的类的对象的Dispose方法能够被调用到,确保可以手动释放任何需要释放的资源。Top

12 楼fengyunleo()回复于 2005-07-30 11:20:57 得分 5

晕了Top

13 楼xfxf521(天使也一样)回复于 2005-07-30 11:26:12 得分 5

这应该就像一个规定样的,你用别人做好的框架,自然要遵守别人定的规矩~~Top

14 楼fayeflash(我爱阿菲)回复于 2005-08-01 13:49:24 得分 0

有几个问题  
  1、我做了个实验:  
  using   System;  
  using   System.IO;  
  using   System.Text;  
   
  namespace   DisposeFinalize的实验  
  {  
  public   class   MyClass  
  {  
  protected   virtual   void   Dispose(bool   disposing)    
  {  
  FileStream   fs   =   new   FileStream(@"..\..\Log.txt",FileMode.Append,FileAccess.Write,FileShare.Read);  
  StreamWriter   sr   =   new   StreamWriter(fs,Encoding.Default);  
  //如果这个方法是被客户直接调用的,那么托管的,和非托管的资源都可以释放    
  if(disposing)    
  {    
  sr.WriteLine(DateTime.Now.ToString()+"->执行MyClass的Dispose方法->释放托管资源");  
  }    
                     
  //释放非托管资源  
  sr.WriteLine(DateTime.Now.ToString()+"->执行MyClass的Dispose方法->释放非托管资源");  
  sr.Close();  
  fs.Close();  
                     
  //如果这个方法是被客户直接调用的,告诉垃圾回收器从Finalization队列中清除自己,  
  //从而阻止垃圾回收器调用Finalize方法  
  if(disposing)      
  GC.SuppressFinalize(this);  
  }  
   
  //可以被客户直接调用    
  public   void   Dispose()    
  {    
  //必须以Dispose(true)方式调用,以true告诉Dispose(bool   disposing)函数是被客户直接调用的    
  Dispose(true);  
  }  
   
  ~MyClass()  
  {  
  Dispose(false);  
  }  
  }  
   
  class   Class1  
  {  
  [STAThread]  
  static   void   Main(string[]   args)  
  {  
  MyClass   MC=new   MyClass();  
  MC.Dispose();  
  Console.ReadLine();  
  }  
  }  
  }  
  我并没有实现IDisposable接口,但是我觉得不耽误我要达到的目的呀,那么为什么还要实现IDisposable接口呢?  
   
  还有呀,MSDN里对Object.Finalize是这么写的:  
  允许   Object   在“垃圾回收”回收   Object   之前尝试释放资源并执行其他清理操作。  
  [C#]   在   C#   中,使用析构函数语法表示终止程序。  
  派生类型中的每个   Finalize   实现都必须调用其基类型的   Finalize   实现。这是唯一一种允许应用程序代码调用   Finalize   的情况。  
  默认情况下,Object.Finalize   不执行任何操作。只有在必要时才必须由派生类重写它,因为如果必须运行   Finalize   操作,垃圾回收过程中的回收往往需要长得多的时间。  
  [C#]   析构函数是执行清理操作的   C#   机制。析构函数提供了适当的保护措施,如自动调用基类型的析构函数。在   C#   代码中,不能调用或重写   Object.Finalize。  
   
  看到这里我有点糊涂了,但是我猜测着理解这些话,是不是应该是这个意思:  
  在C#里,不能override   Finalize这个函数,而且我也做实验了,确实不让,而且提示说让我写析构函数。  
  并且,在析构函数里可以写一些释放非托管资源的代码,当然了,最好是把这些代码写在Dispose函数里,然后调用Dispose(false)。  
   
  请大家帮我解答第一个问题,然后看看我对第二个问题的理解有什么偏颇,谢谢大家了。    
   
   
  Top

15 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2005-08-01 16:33:26 得分 45

第一个问题,你把实现模型里面第一条和第五条结合起来看就可以知道这样做的好处了。  
   
  1、因为你的类会被谁调用是并不可知的。大家都遵循这个规则便可以保证资源一定被释放。  
   
  2、实现了IDispose,结合using语句可以让程序更具可读性。如果上面你的程序中在MyClass   MC=new   MyClass();和MC.Dispose();之间还有别的代码,就应该使用using块保证Dispose一定会被执行,不用(或者语言不支持)using,也应当使用try...finally结构来保证Dispose一定会被执行。  
   
   
  IDispose是一种规则,就像public等修饰符一样,你可以让所有的东西都public而不要private,这是没问题的,如果程序都是你写的话。但是如果你想要与别人协作的话,就应该遵守这些规则。  
   
   
  第二个问题,C#会根据析构函数自动生成Finalize方法。永远不要在析构函数或者Finalize方法中抛出异常,这会导致严重的后果。(.NET的FileStream就有这个问题,将导致某些情况下文件流永远不能关闭。)Top

相关问题

  • 函数的执行顺序
  • VC中函数的求值顺序?????
  • 函数参数的顺序为什么不能变?
  • 关于函数默认参数顺序的一个问题
  • 函数参数的顺序为什么不能变?(续)
  • 函数参数的顺序为什么不能变?(再续)
  • VC++ 中函数执行顺序;请帮忙!!
  • 关于基类、派生类函数执行顺序的问题
  • 关于函数申明顺序的一个怪问题
  • 请教c/c++函数的压栈顺序。

关键词

  • c#
  • 函数
  • 代码
  • 执行
  • 垃圾
  • 接口
  • 调用
  • 析构函数
  • 托管资源
  • 释放

得分解答快速导航

  • 帖主:fayeflash
  • lovvver
  • JzeroBiao
  • xiao_p
  • bflovesnow
  • Roaming_Sheep
  • symboltome
  • fengyunleo
  • xfxf521
  • Ivony

相关链接

  • CSDN .NET频道
  • .NET类图书
  • C#类图书
  • .NET类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo