c#

位置:IT落伍者 >> c# >> 浏览文章

.NET 语言的 using statement 与资源释


发布日期:2022年08月29日
 
.NET 语言的 using statement 与资源释
NET x 的 C#NET 的各种语言中有所谓的 using statement (如本 blog 上一篇帖子「使用ADONET 的NextResult 方法取得多个Result Set」的代码范例)可保证自动 dispose (释放) unmanaged object (对象) 所占用的资源包括因未处理的 exception 而造成区块结束 (但 StackOverflowException 除外)系统都会 dispose 资源因此若您在 using 区块中建立了数据库的 connection即无须再手动 close connection亦无须再下 ConnectionDispose()CommandDispose() 等指令根据 MSDN Library 和目前市面上几本 ADONET 原文书都有提到在 using 区块中会自动去做 dispose 的动作NET 的 garbage collector 会自动释放不再使用的 managed resources 所占用的内存不用程序员手动撰码但 unmanaged resources 则需要程序员自行下 Dispose() 去做处理以让对象彻底终止 unmanaged resources 的使用例如传统的做法常会在 trycatchfinally pattern 中去呼叫 Dispose 方法但若是数据库的联机则必须有不同考虑因为若任意下 Dispose 提早回收也可能导致联机无法有效地被重复引用

现在大部分的数据库和 Data Provider 都有支持 Connection Pooling 机制亦即在建立完数据库的联机后当程序员呼叫 Close 方法关闭一个数据库的 Connection 对象时NET 的 Data Provider 并不会将这个对象所占用的内存空间释放掉而是将此对象暂存至 Pool 之中 以便待会可以再重复使用

若在设定时间 (默认为 秒) 内没有应用程序使用到此对象或是呼叫了 Dispose 方法NET Data Provider 才会真正关闭这个联机并由 Garbage Collector 自动将资源收回因此常有 web 程序员在网络上各讨论区提到是否有必要在呼叫 Close 方法后再呼叫 Dispose 方法并将 Connection 设为 Nothing (或 Null)?答案是不必要的因为 GC 过一阵子就会自动回收未再被参照的联机手动呼叫 Dispose 只不过提早回收的动作而已而且若是该联机可能会在短时间内被大量使用者同时存取的话也应让其待在 Pool 中待命而应避免手动呼叫 Dispose 方法导致它被真正关闭并被回收而无法有效地被重复使用

由于 GC 只会在系统闲置或内存不足时才启动因此除非是使用频率非常繁复的资源否则交由 GC 自行处理即可而设为 Nothing (或 Null) 也只是将 Connection 变量的位置清除 (Null Reference)事实上原来 New 出来的 Connection 对象还是存在而 Dispose 方法是用来处理自行建立的 Windows 资源但又不会自行释放的对象如档案 (开档与关文件)GDI 对象 (直接由 Win API 叫用)…等等

接下来再回头探讨 NET 的 VB/C# 语言中都有的 using statementusing 语句算是简易版的 tryfinally pattern可让程序员以较简便的写法尽早去释放资源尤其最适用在有限的 unmanaged resources 上例如档案和串流 I/OSocket 网络连接File Handle (档案控制代码)COM 组件绘图和字形数据库存取WorkflowRuntime (WF)…等等的内存自动释放using statement 遇到例外时也会抛出例外 (throw)但不会去 catch 处理例外因此若您想要自行处理例外的话只能回归传统的 trycatchfinally 写法

提供给 using statement 的对象必须实作 IDisposable 接口若是自己写的 class只要实作 SystemIDisposable 接口即拥有 Dispose 方法之后若引用 using statement 去释放这个 class 的 instance即会自动做 object 的 Close()Dispose()设定为 null (Nothing) 这三种动作不需要再自己手动处理反而若是自己手动多下一次 Close()会让 CLR 浪费资源多做一次处理反倒会影响程序「性能 (performance)」根据国外网站及 ADONET 书籍证实若 using 语句搭配 CommandBehaviorCloseConnection 一起使用其重复关闭数据库联机的动作会大幅地降低程序性能处理时间甚至会多出 % 以上 (叫用 ExecuteReader() 时若搭配 CommandBehavior 枚举值 (enumerated value)可要求在查询完成后自动关闭数据库联机)

此外using statement 也可多层巢状地使用例如第一层的 using statement 里包 SqlConnection 的宣告及 instance 的新增第二层包 SqlCommand第三层包 SqlDataReader您亦可在巢状的 using statement 中指定多种的系统资源包括数据库的 transaction 交易处理

上一篇:用C#来实现以动画的方式显示图像

下一篇:vs.net中web services入门