现在的位置: 首页 > 综合 > 正文

浅尝EffectiveCSharp_8

2013年01月01日 ⁄ 综合 ⁄ 共 2893字 ⁄ 字号 评论关闭

Item 15: Utilize using and try/finally for Resource Cleanup 使用using 和 try/finally 进行资源清理

使用非托管系统资源的类型应该用Dispose()方法来释放。.NET环境的规则是:使用该类型的代码对它有释放的责任,而不是该类型或者系统。The  rules of the .NET environment make that the responsibility of the code that uses the type, not the responsibility of the type or the system.因此,当你使用的方法有Dispose()方法,那么你应该记得调用Dispose()方法来释放它。保证Dispose()的最好方法就是使用using声明或者是try/finally块。
●C#语言设计者知道明确的释放资源会是a common task。他们增加了关键字来使它更简单。加入你写了一下代码

public void ExecuteCommand(string connString,string commandString)
{
SqlConnection myConnection
= new SqlConnection(connString);
SqlCommand mySqlCommand
= new SqlCommand(commandString,myConnection);
myConnection.Open();
mySqlCommand.ExecuteNonQuery();
}

 在这个例子中,两个可释放对象没有惊醒正确的清理:SqlConnection and SqlCommand。这些对象依然存在在内存中,直到finalizers被调用。下面是一个修改的例子

public void ExecuteCommand(string connString,string commandString)
{
SqlConnection myConnection
= new SqlConnection(connString);
SqlCommand mySqlCommand
= new SqlCommand(commandString,myConnection);
myConnection.Open();
mySqlCommand.ExecuteNonQuery();
mySqlCommand.Dispose();
myConnection.Dispose();
}

这个已经比较好了,除非SQL执行时出现了异常被抛出。那样的话,调用的Dispose()就不会发生。下面使用using声明来保证Dispose()被调用

public void ExecuteCommand(string connString, string commandString)
{
using (SqlConnection myConnection = new SqlConnection(connString))
{
using (SqlCommand mySqlCommand = new SqlCommand(commandString, myConnection))
{
myConnection.Open();
mySqlCommand.ExecuteNonQuery();
}
}
}

无论你什么时候在函数中使用一个可释放 的对象,使用using是保证对象释放的最简单方法。

 

●如果你对一个不支持IDisposable接口的变量使用using,编译器会产生一个错误。比如:如果obj实现IDisposable接口,using声明就会产生清楚代码。

// Does not compile:
// String is sealed, and does not support IDisposable.
using (string msg = "This is a message")
Console.WriteLine(msg);
using声明只有在编译时类型支持IDisposable接口的情况下有用。
// Does not compile.
// Object does not support IDisposable.
using (object obj = Factory.CreateResource())
Console.WriteLine(obj.ToString());

// The correct fix.
// Object may or may not support IDisposable.
object obj = Factory.CreateResource();
using (obj as IDisposable)
Console.WriteLine(obj.ToString());

 

●using声明是一个套一个。现在来看看try/catch块

public void ExecuteCommand(string connString,
string commandString)
{
SqlConnection myConnection
= null;
SqlCommand mySqlCommand
= null;
try
{
myConnection
= new SqlConnection(connString);
mySqlCommand
= new SqlCommand(commandString,myConnection);
myConnection.Open();
mySqlCommand.ExecuteNonQuery();
}
finally
{
if (mySqlCommand != null)
mySqlCommand.Dispose();
if (myConnection != null)
myConnection.Dispose();
}
}

 现在已经解决了两个非常显著的问题,但是这里还有点细微的差别。有的类型既支持Dispose方法也支持Close方法来释放对象。SqlConnection就是这样的一种类型。你也可以这样关闭SqlConnection:

public void ExecuteCommand(string connString,
string commandString)
{
SqlConnection myConnection
= null;
try
{
myConnection
= new SqlConnection(connString);
SqlCommand mySqlCommand
= new SqlCommand(commandString,myConnection);
myConnection.Open();
mySqlCommand.ExecuteNonQuery();
}
finally
{
if (myConnection != null)
myConnection.Close();
}
}

 这里connection并没有被关闭。Dispose方法和Close方法并不完全一样,Dispose在释放了资源后,还通知了GC去处理,它调用了GC.SuppressFinalize()。而Close没有这么做,因此对象依然在finalization队列。如果你能选择,Dispose() is better than Close().

 

 

抱歉!评论已关闭.