Does ADO.NET go overboard with IDisposable?

后端 未结 3 1038
孤独总比滥情好
孤独总比滥情好 2021-01-24 05:24

When .NET first came out, I was one of many who complained about .NET\'s lack of deterministic finalization (class destructors being called on an unpredictable schedule). The co

3条回答
  •  滥情空心
    2021-01-24 06:17

    Yes. almost anything in ADO.Net is implementing IDisposable, whether that's actually needed - in case of, say, SqlConnection(because of connection pooling) or not - in case of, say, DataTable (Should I Dispose() DataSet and DataTable? ).

    The problem is, as noted in the question:

    without understanding the code for each class in some detail, it's hard to be certain which ones I can leave out.

    I think that this alone is a good enough reason to keep everything inside a using statement - in one word: Encapsulation.

    In many words: It shouldn't be necessary to get intimately familiar, or even remotely familiar for that matter, with the implementation of every class you are working with. You only need to know the surface area - meaning public methods, properties, events, indexers (and fields, if that class has public fields). from the user of a class point of view, anything other then it's public surface area is an implementation detail.

    Regarding all the using statements in your code - You can write them only once by creating a method that will accept an SQL statement, an Action and a params array of parameters. Something like this:

    void DoStuffWithDataTable(string query, Action action, params SqlParameter[] parameters)
    {
        using (SqlConnection connection = new SqlConnection(connectionString))
        using (SqlCommand command = new SqlCommand(query, connection))
        using (SqlDataAdapter adapter = new SqlDataAdapter(command))
        using (SqlCommandBuilder builder = new SqlCommandBuilder(adapter))
        using (var table = new DataTable())
        {
            foreach(var param in parameters)
            {
                command.Parameters.Add(param);
            }
            // SqlDataAdapter has a fill overload that only needs a data table
            adapter.Fill(table);
            action();
            adapter.Update(table);
        }
    }
    

    And you use it like that, for all the actions you need to do with your data table:

    DoStuffWithDataTable(
        "Select...",
        table => 
        { // of course, that doesn't have to be a lambda expression here...
            foreach (DataRow row in table.Rows) // search whole table
            {
                if ((int)row["Id"] == 4)
                {
                    row["Value2"] = 12345;
                }
                else if ((int)row["Id"] == 5)
                {
                    row.Delete();
                }
            }
        },
        new SqlParameter[]
        {
            new SqlParameter("@FirstValue", 2),
            new SqlParameter("@SecondValue", 3)
        }
        );
    

    This way your code is "safe" with regards of disposing any IDisposable, while you have only written the plumbing code for that just once.

提交回复
热议问题