Search code examples
c#ado.netusing-statement

What scope does a using statement have without curly braces


I inherited the following code:

    using (var dataAccessConnection = da.GetConnection()) //no opening curly brace here
    using (var command = new SqlCommand(sql, dataAccessConnection.Connection))
    {
        command.CommandType = CommandType.Text;
        using (var sqlDataReader = command.ExecuteReader(CommandBehavior.CloseConnection))
        {
            while (sqlDataReader.Read())
            {
                rueckgabe.Add(new Myclass
                                  {
                                      Uid = Guid.NewGuid(),
                                      ImportVersionUid = versionUid,
                                      MyProperty = Convert.ToInt32(sqlDataReader["MyProperty"])
                                        });       
            }
        }
        command.Connection.Close();
        dataAccessConnection.Connection.Close();
    }

Looking at the code I expexted an opening curly brace after the using clause.

The code compiles and does what it is expected to do. The application behaves unpredictable. At some time it cant access the Database server.

Does this code make sense? Does dataAccessConnection have the rigth scope?


Solution

  • using statements without explicit curly braces apply only to the following statement.

    using (Idisp1)
        // use it
    
    // it's disposed
    

    Thus, when chained, they work the same way. The second using here acts as a single statement.

    using (Idisp1)
        using (Idisp2)
        {
    
        }
    

    Commenter stakx suggested that formatting to make it clear how the compiler reads the using blocks. In reality, these would usually be formatted as the OP encountered:

    using (Idisp1)
    using (Idisp2)
    {
    
    }
    

    That is equivalent to this:

    using (Idisp1)
    {
        using (Idisp2)
        {
    
        }
    }
    

    Notice that the first at the top is always the last to dispose. Thus, in all previous examples, Idisp2.Dispose() is called before Idisp1.Dispose(). That isn't relevant in many cases where you would do something like this, but I believe you should always be aware of what your code will do and make the informed decision not to care.

    An example of this is when reading a web page:

    HttpWebRequest req = ...;
    
    using (var resp = req.GetResponse())
    using (var stream = resp.GetResponseStream())
    using (var reader = new StreamReader(stream))
    {
        TextBox1.Text = reader.ReadToEnd(); // or whatever
    }
    

    We get the response, get the stream, get the reader, read the stream, dispose the reader, dispose the stream, and finally, dispose the response.

    Note, as commenter Nikhil Agrawal pointed out, that this is a language feature regarding blocks that is not specific to the using keyword. For example, the same applies to if blocks:

    if (condition)
        // may or may not execute
    
    // definitely will execute
    

    Versus

    if (condition1)
        if (condition2)
           // will execute if both are true
    
    // definitely will execute
    

    Although you should never, of course, use if statements this way as it's dreadful to read, but I thought it'd help you understand the using case. I'm personally very okay with chaining using blocks.