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?

3

4 Answers

Beginning with C# 8.0, the using keyword can be used as an attribute in the variable declarations of disposable objects (Reference). The semantics is as you would expect -- the objects are auto-disposed at the end of the scope.

        public class Disposable : IDisposable
        {
            string name;

            public Disposable(string name)
            {
                this.name = name;
            }

            public void Dispose()
            {
                Console.WriteLine(name + " disposed");
            }

            public void Identify()
            {
                Console.WriteLine(name);
            }

            static void Main(string[] args)
            {
                using Disposable d1 = new Disposable("Using 1");
                Disposable d2 = new Disposable("No Using 2");
                using Disposable d3 = new Disposable("Using 3");
                Disposable d4 = new Disposable("No Using 4");
                d1.Identify();
                d2.Identify();
                d3.Identify();
                d4.Identify();
            }
        }

Output

Using 1
No Using 2
Using 3
No Using 4
Using 3 disposed
Using 1 disposed
5

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.

8

The C# language specification (Version 5) describes a using statement as:

using-statement:

using ( resource-acquisition ) embedded-statement

That is:

The using statement obtains one or more resources, executes a statement, and then disposes of the resource.

(My emphasis)

So, how then do we end up using it with curly braces? Because the definition of embedded-statement is:

embedded-statement:

block
empty-statement
expression-statement
selection-statement
iteration-statement
jump-statement
try-statement
checked-statement
unchecked-statement
lock-statement
using-statement
yield-statement

And:

The embedded-statement nonterminal is used for statements that appear within other statements

And finally, we discover that block is defined as:

A block permits multiple statements to be written in contexts where a single statement is allowed.

block:

{ statement-listopt }

So basically, curly braces can always be used to take a situation where a single statement is accepted and to instead have multiple statements.

It just so happens that, almost always, we do want to make use of more than one statement, and so the curly-braces tend to be seen as part of if, using, etc statements. Whereas, in fact, they're a separate part of the language.

The existing responses are incorrect or incomplete respectively.

There are two cases actually:

  1. using (var resp = req.GetResponse())

which has a scope for the next statemenet.

but there is also

  1. using var resp = req.GetResponse()

(Note the lack of parantheses after using compared to 1)
Which has block scope, e.g. the current block or method.

So if you are using using var resp = req.GetResponse() inside of the root block of a method, then the using variable will have method scope, actually similar like the defer statement in go.

Note that defer in GO has FUNCTION scope, while using (without parantheses) in C# has BLOCK scope.

Example

public static ILoggerFactory TestLogging()
{
    // dotnet add package Microsoft.Extensions.Logging
    // dotnet add package OpenTelemetry.Exporter.Console

    using ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
    {
        builder.AddOpenTelemetry(options =>
        {
            options.AddConsoleExporter();
        });
    });

    ILogger<Program> logger = loggerFactory.CreateLogger<Program>();
    System.GC.Collect();
    var fac = loggerFactory.CreateLogger<Program>();
    System.Console.WriteLine(fac);


    logger.LogInformation(eventId: 123, "Hello from {name} {price}.", "tomato", 2.99);

    if (logger.IsEnabled(LogLevel.Debug))
    {
        // If logger.IsEnabled returned false, the code doesn't have to spend time evaluating the arguments.
        // This can be especially helpful if the arguments are expensive to calculate.
        logger.LogDebug(eventId: 501, "System.Environment.Version: {version}.", System.Environment.Version);
    }

    return loggerFactory;
}

You see inside the function, you can create a second logger after calling GC.Collect() using loggerFactory.

But when you return loggerFactory from the function, call GC.Collect and want to create another logger, it will throw System.ObjectDisposedException.

var x = TestLogging();
System.GC.Collect();
var log = x.CreateLogger<Program>(); // throws ObjectDisposedException

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Elena Rostova

Elena Rostova

Lead Health, Wellness & Medical Journalist

Elena Rostova holds a Master's degree in Public Health Journalism. She covers groundbreaking medical research, holistic wellness trends, mental health awareness, and nutritional science.

Share this article
Twitter Facebook Pinterest