关于 Connection.Dispose 的警告

Warnings about Connection.Dispose

我收到的警告很少,都是关于处理 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;
            }
        }
    }

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

您要么使用 using 语句要么使用 try/catch/finally 关闭连接,但不能同时使用这两种方法

IDisposable 接口被特别记录为所有实现都应支持被处置任意次数,并且在调用 Dispose 时它们不应该出错(即使是重复调用).他们预计会在处理后使用它们时出错,但如果您多次处理它们则不会。如果该对象实际上在第二次处置调用时抛出对象处置异常,则该错误将出现在 class 中,而不是您的错误(我强烈怀疑连接 class 的作者是否编写了这样的错误)。

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

这不是一个真正的编译器警告,它只是一个代码分析语句,不幸的是,其中许多实际上并不是有问题的迹象。我建议只禁用该警告,因为它完全错误。

正如 Servy 所提到的,这可能只是一个代码分析警告,可以忽略。

现在为您的代码提出一些偏离主题的建议改进:

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

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

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

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

  5. btnGroup参数没有用到,可以去掉

经过一些重构后,您的代码如下所示:

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);
        }
        // Don't forget sqlConnection.Open() could throw an 
        // InvalidOperationException, and you should handle that scenario
        catch (InvalidOperationException 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;
    }
}