Question

According to MSDN If the IDisposable resource of the nested inner using statement contains the resource of the outer using statement, the Dispose method of the nested resource releases the contained resource.

MSDN (http://msdn.microsoft.com/en-us/library/ms182334.aspx) =>

Example Nested using statements (Using in Visual Basic) can cause violations of the CA2202 warning. If the IDisposable resource of the nested inner using statement contains the resource of the outer using statement, the Dispose method of the nested resource releases the contained resource. When this situation occurs, the Dispose method of the outer using statement attempts to dispose its resource for a second time. In the following example, a Stream object that is created in an outer using statement is released at the end of the inner using statement in the Dispose method of the StreamWriter object that contains the stream object. At the end of the outer using statement, the stream object is released a second time. The second release is a violation of CA2202.

But if i try this piece of code the code still works and returns the number count inserted into the table. Which is contradictory towards the MSDN explanation. I would expect the code to crash on the cmd.ExecuteScalar() call because the conn variable is disposed after the first inner using statement. Why is this still working and why isn't the conn variable disposed after the first inner using?

static void Main(string[] args)
{
    var numbers= DoItGetIt();
}

private static int DoItGetIt()
{
    using (var conn = new SqlConnection("Data Source=BestmixSql;Initial Catalog=Test;Integrated Security=True"))
    {
        conn.Open();
        using (var cmd = new SqlCommand())
        {
            cmd.Connection = conn;
            cmd.CommandText = "INSERT INTO [Test].[dbo].[Tabel] VALUES (666)";
            cmd.ExecuteNonQuery();
        }

        using (var cmd = new SqlCommand())
        {
            cmd.Connection = conn;
            cmd.CommandText = "SELECT COUNT(*) FROM [Test].[dbo].[Tabel]";

            var count = cmd.ExecuteScalar();

            return Convert.ToInt32(count);
        }
    }
}
Was it helpful?

Solution

The MSDN example you are talking to is specifically talking to the scenario where the inner object takes posession of the outer object; for example, a StreamWriter can assume responsibility for a Stream. In that scenario, disposing the inner object also causes the outer object to be disposed - but this is not true in the general case.

In particular, a command does not assume responsibility for disposing a connection. Interestingly, a data-reader can assume responsibility, but only via an optional flag.

Many such objects offer flags to let the caller determine whether the inner object should assume responsibility for disposing the outer object. For example, StreamWriter also now offers a constructor-overload with a bool leaveOpen parameter. If you pass this as true, the StreamWriter does not cascade the Dispose().

This is all implementation details of the inner object, when it is specifically written to do this. It is not a default behaviour of the using pattern.


Side note: I would say MSDN is simply wrong here. The correct implementation is the first sample with two using. The second example is non-intuitive, and prone to incorrect implementation. Don't use it. If necessary, use leaveOpen to make is explicit, but frankly it usually works fine without this, if you are about to dispose it anyway.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top