IDisposable接口和析构函数的联合使用

本文详细解析了Dispose模式的实现原理及应用。通过一个具体的C#示例,解释了如何正确使用Dispose()方法进行资源释放,并探讨了Dispose(bool)重载方法的作用及与析构函数的关系。

正确调用Dispose(),同时把执行析构函数作为一种安全机制,以防没有调用Dispose().

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MemRelease
{
    public class ResourceHolder : IDisposable
    {
        private bool isDisposed = false;

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!isDisposed)
            {
                if (disposing)
                {
                    // Cleanup managed object by calling their Dispose() method
                }

                // Cleanup unmanaged objects
            }
            isDisposed = true;
        }

        ~ResourceHolder()
        {
            Dispose(false);
        }

        public void SomeMethod()
        {
            // Ensure object not already disposed before execution of any method
            if (isDisposed)
            {
                throw new ObjectDisposedException("ResourceHolder");
            }

            // Method implementation
        }
    }

    class Program 
    {        
        static void Main(string[] args)
        {
            
        }
    }
}

这段代码里面,Dispose()有第二个proteced重载方法,它带有一个bool参数,这是真正完成清理工作的方法。

最后IDisposable.Dispose()包含一个对System.GC.SuppressFinalize()方法的调用。GC表示垃圾收集器,SuppressFinalize()方法则告诉垃圾收集器有一个类不再需要调用其析构函数。因为Dispose已经完成了所有需要的清理工作,所以析构函数不在需要做任何工作。

 

书上的说法:

 

传递给Dispose(bool)的参数表示Dispose(bool)是有析构函数调用,还是有IDisposable.Dispose()调用 ---- Dispose(bool)不应从代码的其他地方调用,其原因是

  • 如果客户调用IDisposable.Dispose(),该客户就指定应清理所有与该对象相关的资源,包括托管和非托管。
  • 如果调用了析构函数,原则上所有的资源仍需要清理。

【我的看法】

从这个程序上看,实际上是这样的

当用户调用ResourceHolder类的Dispose()方法的时候,运行Dispose(true),释放的是托管对象的资源,然后释放未托管对象资源,最后将isDisposed设置为true,这样析构函数不会被调用。

 

郁闷呢,这里的析构函数岂不是摆样子了,析构函数起什么作用呢?!

转载于:https://www.cnblogs.com/herbert/archive/2010/06/03/1750926.html

<think>好的,我现在需要介绍C#的造函数析构函数。首先,我得回忆一下基本概念,确保自己理解正确。造函数是在创建对象时初始化的方法,而析构函数用于在对象销毁时释放资源。不过,C#中的析构函数其他语言比如C++有些不同,这点需要注意。 接下来,用户可能想知道造函数有哪些类型,比如默认造函数、参数化造函数、静态造函数,还有私有造函数的作用。需要分别解释每种类型,并给出例子。比如,默认造函数没有参数,如果用户不提供,编译器会自动生成。而参数化造函数允许初始化时传入参数,设置对象的初始状态。 静态造函数用于初始化类的静态成员,且只会执行一次。这里要说明静态造函数的特点,比如没有访问修饰符,不能带参数,自动触发等。私有造函数通常用于单例模式或禁止实例化的情况,需要举例说明。 然后是析构函数,C#中的析构函数实际上是通过重写Finalize方法实现的,由垃圾回收器调用。需要注意的是,析构函数不能显式调用,执行时间也不确定。因此,通常建议使用IDisposable接口来管理资源释放,而不是依赖析构函数。 还需要比较造函数析构函数的区别,比如调用时机、用途、是否可重载等。造函数可以重载,析构函数只能有一个,不能继承或重载。此外,资源管理的部分要强调析构函数的不确定性,推荐使用Dispose模式。 在编写示例代码时,要确保语法正确,用中文注释。比如,展示一个类包含不同造函数析构函数的例子,并说明每个部分的作用。同时,提醒用户在实际开发中析构函数使用场景替代方案。 最后,总结两者的主要作用使用注意事项,确保用户理解如何正确使用造函数进行对象初始化,以及析构函数的局限性替代方法。检查是否有遗漏点,比如结体不支持析构函数,或者静态造函数的使用场景是否解释清楚。确保内容结清晰,逐步引导用户理解概念应用方法。</think>### C# 造函数析构函数详解 #### 一、造函数 造函数是用于**初始化对象**的特殊方法,在创建类实例时自动调用。以下是其核心特性: ##### 1. 基本语法 ```csharp public class MyClass { // 无参造函数(默认造函数) public MyClass() { // 初始化逻辑 } // 带参造函数 public MyClass(int value) { // 使用参数初始化 } } ``` ##### 2. 类型说明 | 类型 | 特点 | |-------------------|----------------------------------------------------------------------| | **默认造函数** | 若无显式定义,编译器自动生成;若定义了带参造,需手动添加无参造 | | **静态造函数** | 用`static`修饰,初始化静态成员,整个程序生命周期内只执行一次 | | **私有造函数** | 限制类实例化(如单例模式) | ##### 3. 特殊行为 - **造函数链**:通过`this`调用其他造函数 ```csharp public MyClass() : this(0) { } // 调用带参造函数 ``` - **结体限制**:结体不能定义无参造函数(C# 10+允许,但有严格约束) #### 二、析构函数 析构函数用于在对象销毁时执行资源清理,通过重写`Finalize`方法实现。 ##### 1. 基本语法 ```csharp public class MyClass { ~MyClass() { // 清理非托管资源(如文件句柄) } } ``` ##### 2. 关键特性 - **调用时机不确定**:由垃圾回收器(GC)决定,不可手动调用 - **继承限制**:不能继承或重载 - **性能影响**:含析构函数的对象需要两次GC才能回收 ##### 3. 替代方案 推荐使用`IDisposable`接口实现确定性的资源管理: ```csharp public class Resource : IDisposable { private bool disposed = false; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { // 释放托管资源 } // 释放非托管资源 disposed = true; } } ~Resource() { Dispose(false); } } ``` #### 三、对比总结 | 特性 | 造函数 | 析构函数 | |---------------------|------------------------------|------------------------------| | **调用时机** | 对象创建时 | 对象销毁时(GC触发) | | **可重载性** | 支持重载 | 不可重载 | | **访问修饰符** | 支持public/private等 | 只能为默认(无需修饰符) | | **执行确定性** | 确定执行 | 非确定执行 | | **典型用途** | 初始化对象状态 | 清理非托管资源 | #### 四、最佳实践建议 1. **优先使用`IDisposable`**:对需要及时释放的资源(如文件、网络连接),应实现`Dispose`模式 2. **避免空析构函数**:会增加GC负担且无实际作用 3. **结体限制**:析构函数仅适用于类,结体不支持 4. **异常处理**:析构函数中不要抛出异常,否则可能导致程序崩溃 $$ \text{对象生命周期公式:创建} \xrightarrow{\text{造函数}} \text{使用} \xrightarrow{\text{析构函数/Dispose}} \text{销毁} $$ 通过合理使用造函数`IDisposable`模式,可以有效管理对象生命周期资源释放,提升程序健壮性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值