[登录]
[注册]
|
Visual Studio.NET
JavaScript
Java
C&C++
Flash & Flex
Database
Web
编程应用
编程工具
拼吾爱程序人生
»
软件编程
»
Visual Studio.NET
»
.NET,你忘记了么?(二)——使用using清理非托管资源
.NET,你忘记了么?(二)——使用using清理非托管资源
[
636
浏览 ][
手机版
]
返回列表
发布日期: 2009-03-02 13:32 发布者: cobra
原版编程图书超低价热卖
1
#
字体大小:
t
T
赞助商
我们都知道,垃圾回收可以分为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-catch-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-catch-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。有一个观点我不知道是否正确,曾经也引起过很激烈的讨论,就是异常处理会不会降低程序的性能。如果会的话,那么异常的嵌套是不是会让程序的性能指数型降低呢?所以有个原则是:尽量避免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来进行非托管资源的资源回收。
文/
飞林沙
出处/博客园
赞助商
赞助商
您可能对下面的文章也感兴趣(
返回头部
):
•
全国省市区县最全最新数据表
•
Windows 7 任务栏开发 之 覆盖图标(Overlay Icon)
•
.NET 3.5平台上的Socket开发
•
Visual Studio 2008 C# .net 自已动手制作串口调试助手
•
Programming Entity Framework
•
Windows Moblie 5.0在托管程序中实现短信接收和拦截
•
功能强大的Excel操作组件:GemBox ExcelLite 2.3
•
脱离.Net Framework运行doNet程序的简单方法
•
《Spring.NET框架参考文档》中文版
•
Windows 7 任务栏开发 之 跳转列表(Jump Lists)
•
使用FileSystemWatcher监控网络路径(含源码下载)
•
.NET3.5下的Socket通信框架
•
Windows Mobile 开发入门—开发绚丽滑动效果
•
全国省份,城市,地区全数据(SQL版与XML版)包括各城市邮编
•
Microsoft Visual Studio Tips
•
Professional SharePoint 2010 Administration
TOP
返回列表
WPF
C#
WCF
WF
ADO.Net
建站交流
JavaScript
DB2
帖子标题
作者
我的资料
jQuery
ExtJS
Ajax
Android
JS压缩
Asp.Net
C#
Silverlight
WCF
WPF
WF
Linq
ADO.Net
F#
SQL Server
Oracle
MySQL
DB2
应用系统
框架设计
SEO编程
软件测试
程序人生
算法解析
HTML5