有关Connection.Dispose

时间:2018-11-02 19:27:40

标签: c# ado.net

关于处置SqlConnection的警告很少。

这是我的代码:

public Dictionary<string, MyObject> GetGrpDataFromDB(string btnGrp)
{
    Globals glob = new Globals();
    using (SqlConnection Connection = new SqlConnection((glob.Comms())))
    {
        SqlCommand sql = new SqlCommand("SELECT BrzaGrupaBroj,BrzaGrupaNaziv,BrzaGrupaColor FROM BrzaGrupaGUI", Connection);

        using (SqlDataAdapter adapter = new SqlDataAdapter(sql))
        {
            DataTable dt = new DataTable();
            try
            {
                Connection.Open();
                adapter.Fill(dt);
            }
            catch (SqlException ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                Connection.Close();
            }

            var myDictionary = new Dictionary<string, MyObject>();
            foreach (DataRow row in dt.Rows)
            {
                var newObject = new MyObject(row);
                myDictionary.Add(newObject.brzaGrpBr , newObject);
            }
            return myDictionary;
        }
    }
}

这是确切的警告:

Warning CA2202  Object 'Connection' can be disposed more than once in method 'GetGrpRowsDB.GetGrpDataFromDB(string)'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.

如何仅处置SqlConnection一次,以便摆脱这些警告? :)

编辑:

我尝试不使用Try Catch Finnaly,但即使这样,我也得到完全相同的警告。也许我找错地方了?

 public Dictionary<string, MyObject> GetGrpDataFromDB(string btnGrp)
    {

        Globals glob = new Globals();
        using (SqlConnection Connection = new SqlConnection((glob.Comms())))
        {
            SqlCommand sql = new SqlCommand("SELECT BrzaGrupaBroj,BrzaGrupaNaziv,BrzaGrupaColor FROM BrzaGrupaGUI", Connection);


            using (SqlDataAdapter adapter = new SqlDataAdapter(sql))
            {
                DataTable dt = new DataTable();


                Connection.Open();
                adapter.Fill(dt);
                Connection.Close();


                var myDictionary = new Dictionary<string, MyObject>();
                foreach (DataRow row in dt.Rows)
                {
                    var newObject = new MyObject(row);
                    myDictionary.Add(newObject.brzaGrpBr , newObject);
                }
                return myDictionary;
            }
        }
    }

3 个答案:

答案 0 :(得分:2)

IDisposable接口被专门记录为:所有实现均应支持任意次数的处置,并且在调用Dispose时也不会出错(即使在重复调用时也是如此)。处置它们后,您可能会误以为您会使用它们,但是如果您多次处置它们,则不会出错。如果该对象实际上在第二次dispose调用上抛出了一个对象处置异常,则该错误将在该类中,而不是您的类别中(我强烈怀疑连接类的作者编写了这样的错误)。

没有特别的理由多次处理资源。如果需要,请务必除去多余的处置物,以避免冗余。 (在这种情况下,关闭连接是最有意义的删除方式,这样,创建命令或适配器的任何问题都不会泄漏连接。)

这不是实际的编译器警告,它只是代码分析语句,不幸的是,许多语句实际上并不表示存在问题的迹象。我建议只禁用该警告,因为这完全是错误的。

答案 1 :(得分:2)

如Servy所述,这很可能只是代码分析警告,可以忽略。

现在对代码进行一些偏离主题的建议改进:

  1. 避免在标识符中使用缩写。它使您的代码更难以阅读和理解。

  2. 您可以将using语句链接在一起以减少不必要的嵌套。

  3. SqlCommand也实现了IDisposable;它需要一个using语句。

  4. 当类型明显时,您可以使用var

  5. 未使用btnGroup参数,可以将其删除。

  6. 总是在您的任何更明确的catch (Exception ex)语句之后添加catch。否则,将捕获并吞下非SqlException

这是您的代码经过一些重构后的样子:

public Dictionary<string, MyObject> GetGroupDataFromDatabase()
{
    var globals = new Globals();

    using (var sqlConnection = new SqlConnection((globals.Comms()))) // If you can, I'd rename Comms too.
    using (var sqlCommand = new SqlCommand("SELECT BrzaGrupaBroj, BrzaGrupaNaziv, BrzaGrupaColor FROM BrzaGrupaGUI", sqlConnection))
    using (var sqlAdapter = new SqlDataAdapter(sqlCommand))
    {
        var dataTable = new DataTable();

        try
        {
            sqlConnection.Open();
            sqlAdapter.Fill(dataTable);
        }
        catch (SqlException ex)
        {
            MessageBox.Show(ex.Message);
        }
        // Without this, sqlConnection.Open() could throw an InvalidOperationException 
        // and you would never know.
        catch (Exception ex) 
        {
            // Do something with the exception, like logging
        }

        var myDictionary = new Dictionary<string, MyObject>();

        foreach (var row in dataTable.Rows)
        {
            var newObject = new MyObject(row);
            myDictionary.Add(newObject.brzaGrpBr, newObject);
        }

        return myDictionary;
    }
}

答案 2 :(得分:0)

您可以摆脱代码中的finally块。您将Connection对象的创建包装在using语句中,因此,当作用域离开using块时,它将自动为您处理Connection变量。

您可以使用using语句,也可以使用try / catch / finally关闭连接,但不能同时关闭两者