Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will all objects created inline in a `using` statement be disposed of? [duplicate]

Tags:

c#

using

dispose

This may be answered elsewhere, but after doing a bit of searching I didn't find much on the subject outside of the normal using context.

I am curious if all objects created in a using block will be disposed of as well as the original object.

Here is the context:

Normally I would do something like this:

using (var conn = new SqlConnection(connectionString))
using (var cmd = new SqlCommand(commandText, conn))
{
    //Do everything I need to here
}

I know that both conn and cmd go out of scope at this point and are disposed of because of the lovely using keyword.

I am curious if the same disposal rules would apply to the following statement:

using (var cmd = new (SqlCommand(commandText, new SqlConnection(ConnectionString)))
{
   //Do everything I need here
}

Would the SqlConnection object that was created inline in the using statment be disposed of when cmd goes out of scope and is disposed of because it's associated with the object?

Also which would be syntactically preferred? I personally think the 2nd is cleaner, but I understand readability may come to play here as well.

like image 232
Evan L Avatar asked Feb 18 '14 20:02

Evan L


4 Answers

For your second code, Dispose won't be called on SqlConnection instance when flow leaves using block unless SqlCommand.Dispose() do that internally (and no, it doesn't).

According to specification (8.13), using (ResourceType resource = expression) statement is transformed into:

{
    ResourceType resource = expression;
    try {
        statement;
    }
    finally {
        if(resource != null)
            ((IDisposable)resource).Dispose();
    }
}

In your code, resource is SqlCommand, and that's the one Dispose is called on.

like image 52
MarcinJuraszek Avatar answered Nov 18 '22 20:11

MarcinJuraszek


No.

using statements only apply to the resources declared directly in the statement; not to other allocations in the initializer.

You need a separate using statement for each resource.

like image 21
SLaks Avatar answered Nov 18 '22 21:11

SLaks


According to MSDN, this code:

using (var temp = obj)
{
    // ...
}

Translates to (including the extra curly braces to limit the scope):

{
    var temp = obj;
    try
    {
        // ...
    }
    finally
    {
        if (temp != null)
            ((IDisposable)temp).Dispose();
    }
}

As you can see, if you substitute obj for new SqlCommand(commandText, new SqlConnection(ConnectionString)) then only the SqlCommand gets properly disposed.

{
    SqlCommand temp = new SqlCommand(commandText,
        new SqlConnection(ConnectionString));
    try
    {
        // ...
    }
    finally
    {
        if (temp != null)
            ((IDisposable)temp).Dispose();
    }
}

So, the SqlConnection won't get disposed unless the disposed SqlCommand does that. But it doesn't, and it shouldn't: it didn't create the object, therefore it must not destroy it either.

like image 36
Daniel A.A. Pelsmaeker Avatar answered Nov 18 '22 21:11

Daniel A.A. Pelsmaeker


Certainly there are already answers that explains this correctly. This is covered by the specification as mentioned by others.

But you could just try it out. Here is an example:

static class Program
{
    static void Main()
    {
        using (new DisposeMe("outer", new DisposeMe("inner", null)))
        {
            Console.WriteLine("inside using");
        }
        Console.WriteLine("after using scope");
    }
}

class DisposeMe : IDisposable
{
    public readonly string name;

    public DisposeMe(string name, object dummy)
    {
        this.name = name;
    }

    public void Dispose()
    {
        Console.WriteLine("'Dispose' was called on instance named " + name);
    }
}

Output:

inside using
'Dispose' was called on instance named outer
after using scope

(Of course if you nest two using statements, as in using (var inner = new DisposeMe("inner", null)) { using (new DisposeMe("outer", inner)) { ... } }, the Dispose method is called on both objects.)

like image 39
Jeppe Stig Nielsen Avatar answered Nov 18 '22 19:11

Jeppe Stig Nielsen