news 2026/4/28 3:07:22

C# IDisposable 和 using

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C# IDisposable 和 using

IDisposable 与 using

一、IDisposable:显式释放资源的契约

1. 为什么要使用IDisposable

先看一个问题:C# 会自动清理垃圾,为什么还需要手动释放?
C# 的内存(比如你 new 出来的对象)确实由垃圾回收器(GC)自动管理,你不用管。但是程序里还有一些不属于内存的东西,比如:

  • 文件(你打开了一个文件,就占用了操作系统的文件句柄)
  • 数据库连接(你连上了数据库,数据库服务器那边有资源)
  • 网络端口(你发 HTTP 请求,系统开了端口)
  • 绘图画笔(你画图时用的 GDI 对象)

这些东西,GC 不认识,也不会帮你去关。如果你不主动释放,它们会一直存在,导致:

  • 文件被你的程序一直占着,别人打不开
  • 数据库连接数爆满,新用户连不上
  • 程序越跑越慢,最后崩溃

所以,C# 给了你一个约定:如果你用了这种特殊资源,你用完必须亲自归还。
这个约定就是IDisposable

2. IDisposable 就像一张“归还资源的标签”

C# 源码里面的IDisposable 是一个接口,里面只有一句话:

voidDispose();

任何类(比如 FileStream、SqlConnection)只要实现了这个接口,就等于贴了个标签:“我占用了特殊资源,用完请调用我的 Dispose() 方法归还”。

FileStreamfs=newFileStream("a.txt",FileMode.Open);// ... 使用文件fs.Dispose();// 归还文件

但是这样写有个隐患:如果中间代码抛出异常,Dispose() 可能永远不会执行,资源照样泄露。你还得写 try-finally:

FileStreamfs=null;try{fs=newFileStream("a.txt",FileMode.Open);// 使用文件}finally{if(fs!=null)fs.Dispose();}

太麻烦,而且容易忘。于是 C# 提供了一个语法糖using 。

3. 什么时候自己实现 IDisposable

如果你的类里面包含了需要释放的东西,那么你的类也应该实现 IDisposable。

class Logger : IDisposable{ private FileStream logFile; // 这个需要释放! public Logger(string path){ logFile = new FileStream(path, FileMode.Append); } public void Write(string msg) { // 写日志 } public void Dispose(){ logFile?.Dispose(); // 释放掉内部的资源 } }

然后别人用你的 Logger 时:

using(varlogger=newLogger("app.log")){logger.Write("程序启动");}// 自动释放文件

原则:如果你的类里有任何 IDisposable 类型的成员(比如 FileStream、SqlConnection),你就应该实现 IDisposable,并在 Dispose() 里调用它们的 Dispose()。

二、using 语句:优雅且安全的自动释放

1. using 就是帮你自动写 try-finally 的偷懒工具

using 语句的作用:出了这个大括号,自动调用 Dispose(),不管有没有异常。

基本用法:

using(FileStreamfs=newFileStream("a.txt",FileMode.Open)){// 使用 fs 读文件}// 到这里,自动 fs.Dispose()-----------------------------------------//而上面的using基本用法和下面这段代码实现是一样的FileStreamfs=newFileStream("a.txt",FileMode.Open);try{// 使用 fs}finally{if(fs!=null)fs.Dispose();}

所以 using 的本质 = 自动 + 安全的资源归还

2. 如果用 using 包多个资源

等价于嵌套的 try-finally,保证两个都被释放。

using(FileStreaminput=File.OpenRead("1.txt"))using(FileStreamoutput=File.OpenWrite("2.txt")){// 复制文件内容}// 先自动释放 output,再释放 input

3. C# 8 之后更简单的写法:using 声明

usingvarfs=newFileStream("a.txt",FileMode.Open);// 使用 fs// 方法结束时会自动 Dispose()

效果:fs 的生命周期持续到方法结束,而不是大括号结束。适合那些“在整个方法里都要用,最后一起释放”的场景。

voidReadFile(){usingvarfs=newFileStream("a.txt",FileMode.Open);// 在这里使用 fs// 方法是这里结束,fs 自动释放}

4. 延迟释放与手动控制生命周期

有些场景你不想在代码块结束立刻释放,比如把对象返回给调用方使用。这时就不能在方法内 using。而在创建资源的责任交给调用方,调用方负责 using。

// 不负责释放publicStreamGetStream(){returnnewFileStream("data.bin",FileMode.Open);}// 调用方:using(varstream=GetStream()){// 调用方负责释放}

四、Dispose 模式

如果你写一个类,内部只包含托管资源(例如另一个 IDisposable 对象),只需要:

publicclassMyClass:IDisposable{privateSqlConnectionconn;publicvoidDispose()=>conn?.Dispose();}

这完全正确,对于大多数日常业务代码已经足够。但是,当你面对以下情况时,简单的 Dispose 就不够了:

  1. 类直接持有非托管资源(比如通过 IntPtr 获得的文件句柄、GDI 对象、原生内存)
  2. 类可能被继承,派生类也可能有自己的资源需要释放
  3. 用户可能忘记调用 Dispose,导致非托管资源泄漏
    为了同时解决这三个问题,.NET 设计了一个经典的 Dispose 模式(也叫“可释放模式”),它包含:
  • Dispose() 公共方法
  • protected virtual void Dispose(bool disposing) 方法
  • 终结器(析构函数)
  • GC.SuppressFinalize(this)

Dispose 模式 其实在实际开发并不常见,这里详情就懒得写了
Dispose 模式 = 一个 Dispose() 方法 + 一个受保护的 Dispose(bool) 虚方法 + 一个终结器(仅当有非托管资源时)。

本文参考
阿里云开发者社区 https://developer.aliyun.com/article/805187
C# 官方文档 https://learn.microsoft.com/zh-cn/dotnet/standard/garbage-collection/using-objects
博客园 https://www.cnblogs.com/chenlight/p/16558148.html

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/28 3:05:46

灰色网络深度揭秘:暗网真实生态与安全风险全面解析

1. Hack Forums:不止是技术,更是“灰色地带”的狂欢? 这个2005年就成立的老牌论坛,与其说是“黑客技术交流”,不如说是网络安全灰色地带的缩影。从渗透测试到社工,啥都有,甚至还有交易区…别告…

作者头像 李华
网站建设 2026/4/28 3:05:05

Raycast插件开发实战:本地数据解析与Cursor成本监控实现

1. 项目概述:一个为Raycast设计的Cursor成本监控插件如果你和我一样,日常重度依赖Cursor作为主力代码编辑器,同时又是一个Raycast的忠实用户,那么你很可能也面临过同样的困扰:Cursor的AI功能(特别是其集成的…

作者头像 李华
网站建设 2026/4/28 3:00:29

AI 术语通俗词典:交叉熵

交叉熵是信息论、统计学、机器学习和人工智能中非常常见的一个术语。它用来描述:当真实结果已经给定时,一个概率模型给出的预测分布到底有多“不贴合”真实分布。 换句话说,交叉熵是在回答:模型给正确答案分配的概率到底够不够高。…

作者头像 李华
网站建设 2026/4/28 3:00:23

免费降AI率实用工具盘点:论文轻松过AIGC检测

现在写论文用AI辅助早已是常态,但不少同学都踩过AI率超标的坑:学校和期刊的检测规则越来越严,一旦AI生成痕迹超标,轻则打回修改,重则直接判定不合格,之前花的精力全白费。人工逐句改写不仅耗时长&#xff0…

作者头像 李华
网站建设 2026/4/28 2:59:27

ARM架构缓存与计数器寄存器深度解析

1. ARM架构缓存层次解析在ARM架构中,缓存层次结构通过CLIDR_EL1(Cache Level ID Register)寄存器进行管理和配置。这个寄存器提供了处理器缓存系统的完整拓扑信息,让系统软件能够了解并有效管理各级缓存。1.1 CLIDR_EL1寄存器结构…

作者头像 李华