.NET,你忘记了么?(二)——使用using清理非托管资源
来源:互联网 发布:虚拟社交网络对青年人 编辑:程序博客网 时间:2024/05/22 12:14
我们都知道,垃圾回收可以分为Dispose和Finalize两类,关于这两者的区别已经太多了,一个是正常的垃圾回收GC所调用的方法,另外一个是终结器Finalizer,所调用的方法,在Effective C#一书中,有着明确的建议是说使用IDispose接口来代替Finalize。原因是因为Finalize终结会增加垃圾回收对象的代数,从而影响垃圾回收。
有了上述的原因,我们现在只来看使用IDispose接口的类。
在.NET中,绝大多数的类都是运行在托管的环境下,所以都由GC来负责回收,那么我们就不需要实现IDispose接口,而是由GC来自动负责。可是有一些类使用的是非托管资源,那么这个时候,我们就应该去实现IDispose接口,说个比较常用的SqlConnection之类。
写段常用的连接SQL语句的模型:
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Study1ConnectionString1"].ConnectionString;SqlConnection thisConnection = new SqlConnection(connectionString);thisConnection.Open();SqlCommand thisCommand = new SqlCommand();thisCommand.Connection = thisConnection;thisCommand.CommandText = "select * from [User]";thisCommand.ExecuteNonQuery();thisConnection.Close();其实,作为非托管资源,为了防止我们忘记调用Close,一般都实现了Finalize,因此,即使我们没有Close掉,也会由终结器将这块内存回收。但是,就增加了这块垃圾的代数。
假设说我们写了这样的代码:
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Study1ConnectionString1"].ConnectionString;SqlConnection thisConnection = new SqlConnection(connectionString);thisConnection.Open();SqlCommand thisCommand = new SqlCommand();thisCommand.Connection = thisConnection;thisCommand.CommandText = "select * form [User]"; //SQL语句错误thisCommand.ExecuteNonQuery();thisConnection.Close();这样的话,我们打开的SqlConnection就没有关闭,只能等待Finalize去关闭了。
这是非常不好的做法。于是,我们可以想到异常处理:
SqlConnection thisConnection = null;try{ string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Study1ConnectionString1"].ConnectionString; thisConnection = new SqlConnection(connectionString); thisConnection.Open(); SqlCommand thisCommand = new SqlCommand(); thisCommand.Connection = thisConnection; thisCommand.CommandText = "select * form [User]"; thisCommand.ExecuteNonQuery();}finally{ if (thisConnection != null) { thisConnection.Close(); }}这样做就不错了,但是代码看起来有些丑陋,可是使用using就让代码优雅了很多,这也是C#比JAVA棒很多的地方,呵呵!
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Study1ConnectionString1"].ConnectionString;using (SqlConnection thisConnection = new SqlConnection()){ thisConnection.Open(); SqlCommand thisCommand = new SqlCommand(); thisCommand.Connection = thisConnection; thisCommand.CommandText = "select * form [User]"; thisCommand.ExecuteNonQuery();}
代码量是不是小了很多呢?优雅了许多呢!
其实,在IL的位置,代码仍然是一样的,他同样把代码给编译成了try-finally的处理形式!
接下来,再来看下我们常用的使用数据库的方式:
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Study1ConnectionString1"].ConnectionString;SqlConnection thisConnection = new SqlConnection(connectionString);thisConnection.Open();SqlCommand thisCommand = new SqlCommand();thisCommand.Connection = thisConnection;thisCommand.CommandText = "select * from [User]";SqlDataReader thisReader = thisCommand.ExecuteReader();thisReader.Close();thisConnection.Close();
还是上面的问题,我们考虑用using语句来将之代码重构:
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Study1ConnectionString1"].ConnectionString;using (SqlConnection thisConnection = new SqlConnection(connectionString)){ thisConnection.Open(); SqlCommand thisCommand = new SqlCommand(); thisCommand.Connection = thisConnection; thisCommand.CommandText = "select * from [User]"; using (SqlDataReader reader = thisCommand.ExecuteReader()) { while (reader.Read()) { //操作 } }}我先把这段代码翻译成我们熟悉的try-finally的处理形式:
SqlConnection thisConnection = null;try{ string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Study1ConnectionString1"].ConnectionString; thisConnection = new SqlConnection(connectionString); thisConnection.Open(); SqlCommand thisCommand = new SqlCommand(); thisCommand.Connection = thisConnection; thisCommand.CommandText = "select * from [User]"; SqlDataReader reader = null; try { reader = thisCommand.ExecuteReader(); while (reader.Read()) { //操作 } } finally { reader.Close(); }}finally{ thisConnection.Close();}更丑陋的代码吧!所以有个原则是:尽量避免using语句的嵌套。
怎么样解决呢?很容易,自己写我们的try-finally吧!
SqlConnection thisConnection = null;SqlDataReader reader = null;try{ string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Study1ConnectionString1"].ConnectionString; thisConnection = new SqlConnection(connectionString); thisConnection.Open(); SqlCommand thisCommand = new SqlCommand(); thisCommand.Connection = thisConnection; thisCommand.CommandText = "select * from [User]"; reader = thisCommand.ExecuteReader(); while (reader.Read()) { //操作 }}finally{ if (thisConnection != null) { thisConnection.Close(); } if (reader != null) { reader.Close(); } }这样就好了!
关于using 的这节我就写到这,最后对全文做个总结,其实就是一句话:尽量使用using来进行非托管资源的资源回收。
- .NET,你忘记了么?(二)——使用using清理非托管资源
- 使用using清理非托管资源
- 使用using清理非托管资源
- .NET 清理非托管资源
- 清理非托管资源
- .NET,你忘记了么?(三)——关于Array和List的使用
- .NET,你忘记了么?(三)——关于Array和List的使用
- .net托管资源和非托管资源
- net托管资源和非托管资源
- net托管资源和非托管资源
- .NET 托管资源与非托管资源
- IDispose实现非托管资源清理
- 【清理非托管资源】实现Dispose方法
- C#托管和非托管的资源(二)——后台内存管理
- 托管和非托管资源概念二
- 怎么清理.Net中的非托管代码
- 使用using和try/finally清理资源<.NET资源管理>
- C#托管和非托管的资源(四)——处理非托管资源
- CentOS 修改IP地址 掩码,网关
- 回调函数
- linux系统命令行下载软件——proz
- mysql 在dos底下出现乱码,在navicat lite下不乱码
- 一个程序理解指针与结构的关系
- .NET,你忘记了么?(二)——使用using清理非托管资源
- 千位长整数相加
- libvlc外部api的简单整理
- puppet学习积累
- no java virtual machine was found after searching the following locations
- JavaScript截取上传文件中的文件名
- t-sql导出EXCEL语句
- Oracle 闪回特性(FLASHBACK DROP & RECYCLEBIN)
- Windows7与Window2008 64位IIS7上面配置操作Excel