C#-Dispose 和 Close 的区别

本文详细解释了.NET中Dispose和Close方法的区别与联系,包括如何实现这两个方法以正确管理托管和非托管资源,以及如何在子类中覆盖Dispose方法。

Dispose Close 的区别

DisposeClose基本上是一样的,Close是给不熟悉Dispose的开发者设计的;对于某些类来说,Close更有逻辑性.
.NET的一些class只提供Close,且派生自IDisposable并隐藏了Dispose方法; 这些class,它们其实显式的实现了IDisposable.
Close被设计成public,并且在Close里面显式实现了接口IDisposable中的Dispose方法; 而这个方法里面,又调用了方法Dispose(bool)(此为虚函数,使用protected修饰符),所以你从这些类(只提供Colse的类)中继承的话就必须实现Dispose(bool)这个方法;所以如果你要实现一个有Close的类的话,也需实现Dispose(bool);
        提示:编译器在编译析构函数时,会隐式的把析构函数编译为Finalize()方法的对应代码,确保执行父类的Finalize()方法.
1
//例1
abstract class SysClass : IDisposable
{
    
private IntPtr m_unmanagedResource;
    
private Bitmap m_bitmap;
    
private bool m_disposed = false;

    
public SysClass()
    
{
        m_unmanagedResource 
= Marshal.AllocCoTaskMem(100);
        m_bitmap 
= new Bitmap(50,50);
    }


    
void IDisposable.Dispose() //显式实现
    {
        Dispose(
true); //调用 Dispose(bool)
           //不要再去浪费资源的去执行析构函数了,上面已经执行过啦
        GC.SuppressFinalize(this);
    }


    
//实现Dispose(bool),注意,此为虚函数,使用protected修饰符
       //protected的好处是不让用户有可能主动去调用 Dispose(false)
    protected virtual void Dispose(bool isDisposing) 
    
{
        
if(!m_disposed)
        
{
            
if(isDisposing)
            
{
                
//在此处释放托管资源
                m_bitmap.Dispose(); //m_bitmap就是托管资源
            }

            
//在此处释放非托管资源
            Marshal.FreeCoTaskMem(m_unmanagedResource);
            m_disposed 
= true;
        }

    }


    
public void Close()
    
{
        ((IDisposable)
this).Dispose();
    }


    
~SysClass()
    
{
        Dispose(
false);
    }

}


class MyClass : SysClass //实现一个自己类里的Close
{
    
private IntPtr m_anotherMemory;
    
private Bitmap m_anotherImage;
    
private bool m_disposed = false;

    
public MyClass()
    
{
        m_anotherMemory 
= Marshal.AllocCoTaskMem(20);
        m_anotherImage 
= new Bitmap(25,25);
    }


    
//实现Dispose(bool)
    
//如果传入false,就只释放非托管资源;传入true,全部释放
    protected override void Dispose(bool isDisposing)
    
{
        
if(!m_disposed)
        
{
            
if(isDisposing)
            
{
                
//在此处释放托管资源
                m_anotherImage.Dispose();//m_anotherImage就是托管资源
            }

            
//在此处释放非托管资源
            Marshal.FreeCoTaskMem(m_anotherMemory);
            
base.Dispose(isDisposing);//子类会执行父类的构造函数,这里还需释放父类的
            m_disposed = true;
        }

    }

    
    
~MyClass()
    
{
        Dispose(
false);
    }

}


public static void Main(string[] args)
{
    SysClass sc 
= new MyClass();
    sc.Close(); 
//正确
    sc.Dispose(); //错误
    ((IDisposable)sc).Dispose(); //正确
}
MyClass类和它的父类都使用了双保险(Dispose+析构函数)来释放资源.如果用户调用了Dispose(),不会再调用析构函数(SuppressFinalize的缘故);但如果用户忘记调用Dispose(),就自然会转到析构函数而析构函数本来就具有释放托管资源的能力,所以只要将false传给Dispose就行了.
 
2007-09-08添加
要实现一个具有Dispose功能的类,首先该类要继承自一个具有Close()方法的类,并实现一个Dispose(bool),此函数是一个Protected型的重载函数.
实现过程:
1) Close()里面其实调用了IDisposable接口的Dispose()方法;
2) Dispose方法(此方法需显式实现)里调用了Dispose(bool)方法
3) Dispose(bool)方法里实现了托管和非托管资源的释放.
4) (可选)最好在类的析构函数里实现Dispose(false)方法(flase标记的作用是只释放非托管资源)
5) (可选)子类的释放自身资源的同时也要释放父类中的资源(如果父类在构造函数中生成了资源).我觉得,就算父类的构造函数中没有生成资源,也最好在子类中实现一下.(见上例 base.Dispose(isDisposing);)
6) 注意使用类的对象调用Dispose()方法时的写法.(见上例)
### C# WinForms 中 `Close` `Dispose` 方法的区别 #### 定义与作用 在 C# WinForms 开发中,`Close` `Dispose` 是两个用于释放资源的方法,但它们的作用范围触发时机有所不同。 - **`Close` 方法** 调用窗体的 `Close` 方法会关闭当前窗体实例并触发一系列事件链。这包括调用窗体的 `FormClosing` `FormClosed` 事件[^4]。当窗体被关闭时,其生命周期结束,并可能进一步调用内部对象的 `Dispose` 方法来清理未托管资源。 - **`Dispose` 方法** `Dispose` 方法主要用于显式释放由类持有的未托管资源(如文件句柄、网络连接等)。它是 .NET 的 IDisposable 接口的一部分,通常通过实现 `IDisposable` 来定义如何释放这些资源。对于控件或窗体而言,调用 `Dispose` 不仅会销毁该对象本身,还会递归地对其子控件调用 `Dispose`。 #### 实现机制 两者的底层实现存在显著差异: - 当调用 `Close` 时,它实际上会在适当的时候间接调用 `Dispose`,但这取决于具体的上下文环境以及窗体的设计模式。例如,在 MDI 子窗体中,父容器可能会阻止某些情况下自动执行 `Dispose` 操作。 - 对于 `Dispose`,一旦手动调用了此方法,则无论任何条件都会立即清除关联的对象及其依赖项。这意味着如果过早调用可能导致其他部分程序无法正常访问已处置的数据结构或设备接口。 #### 使用场景比较 | 特性 | `Close` | `Dispose` | |--------------------|----------------------------------|---------------------------------| | 主要用途 | 关闭窗口 | 显式释放资源 | | 是否触发事件 | 是 (FormClosing/FormClosed) | 否 | | 自动回收行为 | 可能会调用 Dispose | 总是彻底摧毁目标对象 | | 常见应用场景 | 用户交互结束后退出某个对话框 | 需要在特定时刻强制释放内存时 | 需要注意的是,在实际编码过程中应当遵循良好的实践原则——即只应在必要时候才直接操作 `Dispose`;而大多数日常需求都可以依靠标准流程中的 `Close` 函数完成相应任务。 ```csharp // 示例代码展示 Close Dispose区别 public partial class MainForm : Form { private ChildForm child; public MainForm() { InitializeComponent(); this.child = new ChildForm(); // 创建一个子窗体实例 this.child.Show(); // 展示这个子窗体 } protected override void OnFormClosing(FormClosingEventArgs e){ base.OnFormClosing(e); if(this.child != null && !this.child.IsDisposed){ this.child.Close(); // 正确做法:先尝试优雅地关闭子窗体 // 如果需要立刻释放所有资源可以用下面一句代替: // this.child.Dispose(); } } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值