48

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?

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
Mathias F
  • 15,906
  • 22
  • 89
  • 159
  • [Nested using statements in C#](http://stackoverflow.com/questions/1329739/nested-using-statements-in-c-sharp) – Soner Gönül Jul 18 '14 at 07:36
  • One commenter at the link said "And it looks as if the first using statement is empty and unused.". Thats what happened to me. But I see now that it is actually a clean style. – Mathias F Jul 18 '14 at 08:45
  • "using" works just like "if". Even if I personally use braces it works without if a single element followes – Ole Albers Jul 18 '14 at 09:09

4 Answers4

73

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
Gopi Reddy
  • 1,170
  • 9
  • 9
  • 6
    So, maybe I'm missing something but what's the point of this? Would declaring a variable in a function/method and using this method not have the same results? – Arvo Bowen Jan 08 '21 at 17:02
  • 3
    I think moving the static `Main` method outside of class `Disposable` would make the example a little easier to understand. – Andrius R. May 19 '21 at 11:21
  • 6
    This is nice info, but the question from 2014 did not use the C# 8 feature! Pay attention to whether the `using` word is followed by a `( ... )` or not. For example, the statement `using Disposable d1 = new Disposable("Using 1");` like in your example, declares the `d1` variable which is in scope for the rest of the method (or whatever block we are inside) and will disposed when control leaves. In contrast, `using (Disposable d1 = new Disposable("Using 1"));` is the old style syntax where the scope of the variable `d1` is only the empty statement `;` seen in the end! Here `;` is like `{ }`. – Jeppe Stig Nielsen Nov 24 '21 at 09:15
  • 5
    So while the info in this answer may be what people are typically looking for today, the resolution of the _original_ 2014 question is what is seen in the other answers here. The scope of the first `using` statement is the immediately following (embedded) `using` statement. – Jeppe Stig Nielsen Nov 24 '21 at 09:18
  • Why is 3 disposed before 1? Does it work itself up to first declared? – Tom Aug 23 '23 at 18:17
45

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.

Matthew Haugen
  • 12,916
  • 5
  • 38
  • 54
  • 2
    More accurately, I'd say they apply to the following statement (which, as you observe, may actually run over multiple lines) – Damien_The_Unbeliever Jul 18 '14 at 07:39
  • @Damien_The_Unbeliever Right! That's the word I was looking for. I'll edit my answer. Thanks. – Matthew Haugen Jul 18 '14 at 07:41
  • @MatthewHaugen: You can add: This blocks behaviour is implemented in language and is not specific to using. – Nikhil Agrawal Jul 18 '14 at 07:49
  • @MatthewHaugen: +1. If you indented the second `using` in the 2nd code example, that would make it extra-clear how a "chained" `using` is the same thing as the first code example. – stakx - no longer contributing Jul 18 '14 at 07:49
  • Good suggestions guys, I've added them in. – Matthew Haugen Jul 18 '14 at 07:55
  • @MatthewHaugen: I think nested if-else blocks are a more interesting example than nested if blocks, since most people feel perfectly comfortable eliding the curly braces in the else block of `if(foo){}else{if(bar){}}`. – Brian Jul 18 '14 at 13:23
  • 2
    @MatthewHaugen - things have changed since C# 8.0, right? – Homer Feb 05 '20 at 21:01
  • 6
    @Homer yes and no--things have definitely gotten added, but what I say here is still true. The "simple using statement" doesn't have parens. So `using (var resp = req.GetResponse())` still only holds scope for the next line, but `using var resp = req.GetResponse()` will be around until the end of the block. I'll edit next time I get a chance. – Matthew Haugen Feb 07 '20 at 15:16
3

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.

Community
  • 1
  • 1
Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
0

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
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442