我有以下代码从db检索数据,当我从Visual Studio运行代码分析时,它建议我在SqlConnection
,DataTable
和SqlDataAdapter
对象上调用dispose方法
SqlConnection sqlconn = new SqlConnection(ConfigurationManager.ConnectionStrings["connstr"].ConnectionString);
SqlCommand cmd = sqlconn.CreateCommand();
cmd.CommandText = "SELECT * FROM tbl_serial WHERE serial = @serial";
cmd.Parameters.AddWithValue("@serial", txtQuery.Text);
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter();
try
{
sqlconn.Open();
da.SelectCommand = cmd;
da.Fill(dt);
}
catch (SqlException ex)
{
lblStatus.Text = ex.Message;
}
finally
{
sqlconn.Close();
}
if (dt.Rows.Count > 0)
{
lblStatus.Text = "FOUND!";
}
else
{
lblStatus.Text = "NOT FOUND!";
}
这是我第一次这样做,我在sqlconn
上调用了dispose方法就像这样 -
finally
{
sqlconn.Close();
sqlconn.Dispose();
}
然而,Visual Studio警告我这样 -
CA2202:Microsoft.Usage:对象'sqlconn'可以多处理 一次在方法'test_search.Unnamed1_Click(object,EventArgs)'中。至 避免生成不应调用的System.ObjectDisposedException 在物体上多次处理:线条:41
所以我想知道何时应该正确调用dispose方法。
答案 0 :(得分:6)
不是直接调用dispose
,而是使用using
statement,当代码执行移出其关联的块时,它将确保为您执行此操作。 E.g:
SqlConnection con;
using (con = new SqlConnection(/* ... */)) {
// Do your stuff with `con`
}
这是一般用于一次性用品的模式。
答案 1 :(得分:3)
这是您的代码重写,无需手动Dispose
/ Close
全部
using (var sqlconn = new SqlConnection(ConfigurationManager.ConnectionStrings["connstr"].ConnectionString))
using (var cmd = sqlconn.CreateCommand())
{
cmd.CommandText = "SELECT * FROM tbl_serial WHERE serial = @serial";
cmd.Parameters.AddWithValue("@serial", txtQuery.Text);
using (var dt = new DataTable())
using (var da = new SqlDataAdapter())
{
try
{
sqlconn.Open();
da.SelectCommand = cmd;
da.Fill(dt);
}
catch (SqlException ex)
{
lblStatus.Text = ex.Message;
}
lblStatus.Text = dt.Rows.Count > 0 ? "FOUND!" : "NOT FOUND!";
}
}
答案 2 :(得分:2)
处理连接处理的最佳方法是 使用
所以你的代码会变成这样,
using(SqlConnection sqlconn = new SqlConnection(ConfigurationManager.ConnectionStrings["connstr"].ConnectionString))
{
code here..
}
由于Sqlconnection实现了IDisposable,因此使用block会在调用完成后自动配置对象。
答案 3 :(得分:1)
sqlconn.Dispose()
在最后一个块中只是多余的。一个Close()实际上调用了Dispose(),这就是Dispose的特定调用抛出错误的原因。
关闭和处置之间存在细微差别。
在你的情况下非常清楚,关闭反过来调用了Dispose。 因此,您第二次调用Dispose会导致异常。
始终使用USING作为更好的方法。
答案 4 :(得分:1)
using(SqlConnection sqlconn = new SqlConnection(ConnectionStrings))
{
//Automatically this block will disposes the SqlConnection
}
or
you can dispose all your objects in Finally Block
答案 5 :(得分:1)
我同意using
上的其他人使用此绝对是最佳做法。但是,您应该将finally
块更改为:
finally
{
if (sqlconn != null)
{
if (sqlConn.ConnectionState == ConnectionState.Open) sqlconn.Close();
sqlConn.Dispose();
GC.SuppressFinalize(sqlConn);
sqlConn = null;
}
}
使用GC.SuppressFinalize
,您告诉垃圾收集器不要因处理sqlConn
而烦恼,因为您已经处理掉它。尽管可以这样做,但我始终认为最佳做法是在您的对象上实施IDisposable
并处理合同Dispose
方法中的所有清理工作 - 同时调用GC.SuppressFinalize(this)
在你的对象上。
public class MyObject : IDisposable
{
private SqlConnection _sqlConn;
public MyObject()
{
_sqlConn = new SqlConnection("connection string");
_sqlConn.Open();
}
void IDisposable.Dispose()
{
if (_sqlConn != null)
{
if (_sqlConn.ConnectionState == ConnectionState.Open)
{
_sqlConn.Close();
}
_sqlConn.Dispose();
_sqlConn = null;
}
// tell the garbage collector to ignore this object as you've tidied it up yourself
GC.SuppressFinalize(this);
}
}
这个previous SO post对这个问题有最好的答案。
答案 6 :(得分:1)
嗨,如果代码中发生异常,最好在最后处理并关闭语句,因为它会执行。
finally
{
sqlconn.Close();
SqlConnection.ClearAllPool(); // this statement clears pool
sqlConn.Dispose();
}
当您关闭或处置连接时,它不会同时关闭连接。只有在刷新appdomain时才会关闭或清除连接池
答案 7 :(得分:0)
您可能希望像这样格式化代码:
using (var sqlconn = new SqlConnection(...)){
try {
sqlconn.Open();
da.SelectCommand = cmd;
da.Fill(dt);
}
catch (SqlException ex) {
lblStatus.Text = ex.Message;
}
}
if (dt.Rows.Count > 0)
{
lblStatus.Text = "FOUND!";
}
else
{
lblStatus.Text = "NOT FOUND!";
}
这样,您可以让using
语法处理/关闭您的连接,而您的代码则专注于对您来说很重要的逻辑。