Reputation: 2610
The consensus on best practice for resource-intensive operations, such as opening database connections, seems to be to use Using
blocks, because the Using
block "guarantees disposal of the resource... even in the case of an unhandled exception.".
Here is how most examples I've found are written:
Sub ExecuteCommand(ByVal sql As String, ByVal connectionString As String)
Using connection As New SqlConnection(connectionString)
Dim command As New SqlCommand(sql, connection)
command.Connection.Open()
command.ExecuteNonQuery()
End Using
End Sub
But nested Using
blocks are allowed, and I occasionally (but rarely) see the above written as:
Sub ExecuteCommand(ByVal sql As String, ByVal connectionString As String)
Using connection As New SqlConnection(connectionString)
Using command As New SqlCommand(sql, connection)
command.Connection.Open()
command.ExecuteNonQuery()
End Using
End Using
End Sub
My question: Is there any benefit to multiple nested Using
blocks? Or does a single Using block already guarantee that all of the resources it contains will be disposed?
(Note: my code is in VB.NET, but the same question applies to C#.)
Upvotes: 5
Views: 2780
Reputation: 9134
Nested using
statements are quite useful. However many programmers don't consider that the SqlCommand
object needs to have resource cleanup. I.e., the resource is the connection, not the command.
ADDED
SqlCommand does not have a Close() method, so even though SqlCommand has a Dispose() method, the lack of a Close() method indicates that there is really "nothing to close / release". Disposable instances will always be Disposed eventually. Hard to find something authoritative without digging through source, but when asked in this article the MS guy was asked exactly what it disposed, he said "Actually not a lot ..." and went on to suggest a USING clause for the SqlCommand(), so I answered the question correctly, but avoided the fuzziness behind it initially.
Upvotes: 1
Reputation: 73482
All other answers are correct. I'll add one more point.
If objects are of same type c# compiler provides a way(syntatic sugar) to use multiple objects in single using
statement inline.
C# version
using (MemoryStream ms1 = new MemoryStream(), ms2 = new MemoryStream())
{
}
Vb.Net version
Using ms1 = New MemoryStream(), ms2 = New MemoryStream()
End Using
This will dispose both the MemoryStream
s
Upvotes: 1
Reputation: 660159
the using block "guarantees disposal of the resource... even in the case of an unhandled exception."
Take that "guarantee" with a grain of salt. Many things can prevent the disposal of the resource. What if the using block contains an infinite loop? Or the block throws an exception, a hostile exception filter higher on the stack goes into an infinite loop and never returns control to the finally block associated with the using statement? Or the block calls Environment.FailFast? There are many, many things that can prevent the disposal from ever running. Never write a program that relies on disposal for its correctness. Disposal is there for politeness, to return scarce resources to the pool for others to use them.
Moreover, let me make sure this point is clear: truly unhandled exceptions are implementation-defined behavior in C#. The using
block's finally clause is there to deal with the situation where an exception is thrown inside the using block and then handled somewhere else, not to deal with the situation where an exception is thrown inside the block and never handled. If that happens then it is entirely up to the implementation to determine what happens; the C# language makes a total of zero promises about the behavior of a program that throws an exception that is never handled. The resources might be disposed. They might not. You're in a building that is about to be unexpectedly demolished; do you really want to spend time washing the dishes and putting them away neatly?
Is there any benefit to multiple nested Using blocks?
Yes.
Does a single Using block already guarantee that all of the resources it contains will be disposed?
No. Only the resources that are actually mentioned by a using statement are cleaned up. That's why you nest them.
There are a few cases where technically you don't have to because the inner one takes responsibility for releasing the same resource as the outer one. But it doesn't hurt anything to nest using blocks and it makes it very clear to the reader what is going on. The best practice here is to have one using statement for every resource that you want cleaned up.
Upvotes: 10
Reputation: 726669
Nested using
blocks are definitely useful: a single block will call Dispose
only on its own variable, not on other variables that may be opened inside the same block. That is why each variable that you want to clean up at a defined point in your program (which should be every variable of type implementing IDisposable
) needs its own using
block.
Upvotes: 8
Reputation: 887509
The Using
statement will dispose the variables declared within the Using
line.
It has no effect on variables declared elsewhere in the block.
You should always use a Using
statement for every disposable variable.
Upvotes: 3