SqlCommand类的Microsoft文档提供了以下示例代码,这些代码不处理SqlCommand。
SqlCommand继承自实现IDisposable的DbCommand。
众所周知,建议丢弃SqlCommand,但本例并非如此。
该示例是否提供了最佳实践?
private static void ReadOrderData(string connectionString)
{
string queryString =
"SELECT OrderID, CustomerID FROM dbo.Orders;";
using (SqlConnection connection = new SqlConnection(
connectionString))
{
SqlCommand command = new SqlCommand(
queryString, connection);
connection.Open();
using(SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
reader[0], reader[1]));
}
}
}
}
在您的代码第一中查看我的评论
private static void ReadOrderData(string connectionString)
{
string queryString = "SELECT OrderID, CustomerID FROM dbo.Orders;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
connection.Open();
using(SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}", reader[0], reader[1]));
}
} // -- disposes reader and closes connection
} // -- disposes connection and closes it
}
command
是在连接using
的范围内声明的,即try/catch/finally
命令不一定持有连接之外的任何资源。并且您正在处理连接,当读取器被处理时,该连接已经关闭。(参见CommandBerhavior
)。因此,最终,command
是保存对已处理资源的引用的对象。
为了更好地了解,使用一些反射工具并向内看。
protected override void Dispose(bool disposing)
{
if (disposing)
this._cachedMetaData = (_SqlMetaDataSet) null;
base.Dispose(disposing);
}
那么,这个元数据是什么?可能是一些参数信息。但是如果你不添加参数,那么你可能就没有什么可处理的了。Microsoft知道这一点,并认为没有必要在command
中包含dispose
。这就是为什么微软没有在command
中包含using
。
看看构造函数
public SqlCommand()
{
GC.SuppressFinalize((object) this);
}
看起来一开始没有什么可处理的。所有这些";缓存项目";将正常进行垃圾收集。我在那里找不到任何IO或其他非托管资源。
然而,需要记住的一点是,实现可能会随着版本的变化而变化,并且您不想更改代码。因此,添加另一层命令
private static void ReadOrderData(string connectionString)
{
string queryString = "SELECT OrderID, CustomerID FROM dbo.Orders;";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(queryString, connection))
{
. . . . . .
}
}
这可能会节省一些时间。
有趣的事实:当使用实现与SqlClient
相同接口和基类的MySql
提供程序时,MySqlCommand.Dispose
中存在一个错误(可能仍然存在),它总是关闭读取器。与using
相同的代码可以使用SqlClient和OracleODP,但不能使用MySql。我必须包装MySqlCommand
,并在提供者不可知的代码中使用我的自定义类(想想Decorator模式)来覆盖行为。