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
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.