何时何地调用dispose方法c#?

时间:2012-10-29 11:13:27

标签: c# asp.net

我有以下代码从db检索数据,当我从Visual Studio运行代码分析时,它建议我在SqlConnectionDataTableSqlDataAdapter对象上调用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方法。

8 个答案:

答案 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。 因此,您第二次调用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语法处理/关闭您的连接,而您的代码则专注于对您来说很重要的逻辑。