55

I was browsing a coworkers c# code today and found the following:

    using (MemoryStream data1 = new MemoryStream())
    using (MemoryStream data2 = new MemoryStream())
    {
        // Lots of code..........
     }

I had always seen the using statement followed by a pair of curly braces that defined the scope of the object life. My coworker who wrote the code said that the curly braces for the data1 using statement weren't needed and the code did the same thing as if they were present and nested the data2 using statement. So, what happens when the curly braces are ommitted?

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
DaveB
  • 9,470
  • 4
  • 39
  • 66
  • 3
    Just my 2 cents - While you "can" do this, as demonstrated by the answers, I'm of the opinion that you shouldn't do it, for readability purposes. To me, it's just like wrapping the if/else/while/lock/etc. blocks in braces - even if they're not necessary, it's much easier to read. – Joe Enos Aug 17 '10 at 21:54
  • 15
    In my opinion, stacked `using` statements, as above, are **far** more readable than nested `using` statements. Particularly in cases where you're chaining together 3-4 Streams/StreamReaders to perform a single set of operations. – Joel Mueller Aug 17 '10 at 22:36
  • 4
    @Joel: Maybe like anything else, the specific situation should be taken into consideration. If it was just two, my opinion is to absolutely nest them with braces. If we're talking 4 like you say, maybe stacked is the better approach. But the first time you need to access data1 prior to data2's creation, it means changing the readability of the code instead of just adding a line of code. – Joe Enos Aug 17 '10 at 23:16
  • @Joe: Fair enough. In my experience, my usage of things involving `using` blocks tends to be rather cut and dried. I don't think I've ever had an occasion to insert some logic in between two stacked `using` statements, and I rarely have to modify them in any way once they're written. – Joel Mueller Aug 18 '10 at 17:56
  • I'm on team "no braces" or "use c#8 way without braces at all", _but_ another idea might be to do all your nested usings and simply outsource the inner code to a method. Then it is very easy to read. ```using (var data1 ...) { using (var data2 ...) { using (var data3 ...) { MethodCall(data1, data2, data3); } } }``` – ecth Aug 31 '21 at 13:57

8 Answers8

111

Yes, you can also put them in one using statement:

using (MemoryStream data1 = new MemoryStream(), 
                    data2 = new MemoryStream())
{
    // do stuff
}
Albin Sunnanbo
  • 46,430
  • 8
  • 69
  • 108
  • I'm pretty sure that the behaviour of this construct is different in certain cases. I don't remember exactly why right now, but I believe I read it in one of Bill Wagners books. – fearofawhackplanet Aug 17 '10 at 22:30
  • Which is disposed first in this case? – fletcher Aug 17 '10 at 22:37
  • 28
    Note that you can only put multiple objects in a single `using` statement if they are all of the same type, `MemoryStream` in this case. – LukeH Aug 17 '10 at 23:39
  • 1
    @fearofawhackplanet: There's no difference in behaviour according to the C# spec. – LukeH Aug 17 '10 at 23:41
  • 1
    @fletcher: They're disposed in exactly the same order as standard nested `using` statements. – LukeH Aug 17 '10 at 23:42
  • 5
    From the C# spec: "A `using` statement of the form `using (ResourceType r1 = e1, r2 = e2, ..., rN = eN) statement` is precisely equivalent to a sequence of nested `using` statements: `using (ResourceType r1 = e1) using (ResourceType r2 = e2) ... using (ResourceType rN = eN) statement`" – LukeH Aug 17 '10 at 23:42
  • @LukeH: I checked the Wagner book and I was wrong, the gotcha he talks about is only when calling the objects constructor outside the using scope with multiple objects. It's a side effect of his recommended use of `as` in the using declarations, which I don't generally agree with anyway. Thanks for finding the quote from the spec to clear that up. – fearofawhackplanet Aug 18 '10 at 08:51
  • As of C# 8.0, you don't need any bracket at all. Simply use "using declarations" (see: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#using-declarations). – Dejan Jun 15 '21 at 12:02
23

From C# 8 you can also use this syntax without any braces:

using var foo = new Foo();
var bar = foo.Bar();

foo will then be disposed at end of its scope (usually at the end of a method) - so be mindful where & when to use.

Reference - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement#example

JvR
  • 1,022
  • 1
  • 11
  • 29
  • 6
    Just got caught out by this new syntax: I had a block of code which had one of these new "using"s in it and I refactored it out to a new method which returns the disposable object. Of course that caused a runtime error. If the braces had been there it would have been a clear indication as to the scope of the variable, and a warning that it wasn't a simple refactor. – Andy Mar 27 '20 at 19:16
22

The same rules apply when you omit the curly braces in a for or an if statement.

Incidentally if you reflect into the compiled code, the compiler decompiler adds the braces.

Chuck Conway
  • 16,287
  • 11
  • 58
  • 101
  • 2
    One difference is that, when nesting `for` statements, we would indent the inner one, but nested `using` statements are usually left-aligned. This is a matter of common convention, not language syntax, of course. – Steven Sudit Aug 17 '10 at 20:27
  • 7
    +1, nitpick point: The compiler does not actually add braces, the decompiler puts them in. – JaredPar Aug 17 '10 at 20:30
18

Exactly what he said. The code above is exactly the same as writing:

using (MemoryStream data1 = new MemoryStream()) 
{
    using (MemoryStream data2 = new MemoryStream())
    {
        // Lots of code
    }
}

You can omit the curly braces after an if/else/for/while/using/etc statement as long as there is only one command within the statement. Examples:

// Equivalent!
if (x==6) 
    str = "x is 6";

if(x == 6) {
    str = "x is 6";
}

// Equivalent!
for (int x = 0; x < 10; ++x) z.doStuff();

for (int x = 0; x < 10; ++x) {
    z.doStuff();
}

// NOT Equivalent! (The first one ONLY wraps the p = "bob";!)
if (x == 5) 
p = "bob";
z.doStuff();

if (x == 5) {
   p = "bob";
   z.doStuff();
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Stephen
  • 6,027
  • 4
  • 37
  • 55
4

This is viable but risky, because if somebody later decides they want to do something to data1 before other stuff happens to it, they might place it right after the data1's using, which would take it out of the entire scope of data2's using. This would likely break compilation but still is a risky and pointless syntax shortcut..

Jimmy Hoffa
  • 5,909
  • 30
  • 53
  • 12
    That person should probably consider a different line of work. – spoulson Aug 17 '10 at 22:16
  • 1
    @spoulson: true of so many people who don't, but it's still our jobs to keep the code as maintainable by others as possible, lest others put bugs in our code.. – Jimmy Hoffa Aug 18 '10 at 12:03
3

Exactly what your colleague said, that is the equivalent of nesting the statements. The dispose for data2 would be called immediately before the dispose function for data1.

fletcher
  • 13,380
  • 9
  • 52
  • 69
2

As people have said: given there only being one line following a statement it will work without the curled braces. However, people are neglecting to show in their examples that that one line can be an if/using/for with it's own curled braces. Here is an example:

if(foo)
  if(bar)
  {
     doStuff();
  }
IAmJersh
  • 742
  • 8
  • 25
1

If there is only one instruction which follow the statement, the bracets are not needed. It is just like with if statement.

if(true)
{
   Console.Writeline("hello")
}

means the same that

if(true)
   Console.Writeline("hello")
jwaliszko
  • 16,942
  • 22
  • 92
  • 158