不像Microsoft文档中的示例那样处理SqlCommand是否正确



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模式)来覆盖行为。

最新更新