5

I understand that any time I am instantiating a class that implements IDisposable, I should use the using keyword in order to ensure that it's disposed of properly.

Like so:

using (SecureString s = new SecureString())
{

}

The above is easy for me to understand - I can use s however I want within those brackets, but once I leave those brackets, I can no longer refer to s. The scope is easy to see.

But what I don't understand is how it works when you use using with no enclosing brackets.

private void Function()
{
    // Some code here

    using (SecureString s = new SecureString())

    // more code here
}

You aren't required to use brackets at all... so... how do I know where I am able to use the object and where it gets disposed, if there are no brackets to go with the using keyword?

PaperBirdMaster
  • 12,806
  • 9
  • 48
  • 94
Ryan Ries
  • 2,381
  • 1
  • 24
  • 33
  • 8
    Just like `if` or `for` without brackets. – Vladimir Oct 17 '13 at 14:22
  • Aside: Actually there are edge cases where this is the wrong thing to do: http://stackoverflow.com/questions/573872/what-is-the-best-workaround-for-the-wcf-client-using-block-issue – millimoose Oct 17 '13 at 14:23
  • You could just try it out. It's pretty easy to figure out with some simple experimentation... – Servy Oct 17 '13 at 14:27
  • @VladimirFrolov Ohhh thank you. That makes total sense. I feel silly for not realizing that now. – Ryan Ries Oct 17 '13 at 14:27

12 Answers12

8

In almost every case in C# when you have the choice of using braces you can substitute them with a single line of code.

Consider an if statement:

if (someBool)
    DoSomething();
else
    DoSomethingElse();

That is just as valid as the following:

if (someBool)
{
    // do lots of things
}
else
    DoSomethingElse();

This is probably almost universally true for any time you can use the { and } brackets.

The nice thing about this with the using statement is that you can nest them like this:

using (var stream = new NetworkStream(...))
using (var sslStream = new SslStream(stream))
using (var reader = new StreamReader(sslStream))
{
    reader.WriteLine(...);
}

This is equivalent to the following:

using (var stream = new NetworkStream(...))
{
    using (var sslStream = new SslStream(stream))
    {
        using (var reader = new StreamReader(sslStream))
        {
            reader.WriteLine(...);
        }
    }
}

Although I think you'd agree it's much nicer looking.

Trevor Elliott
  • 11,292
  • 11
  • 63
  • 102
  • Wow, 10-12 correct answers to my question within 5 minutes. I don't know which answer to pick. I feel dumb for asking such an obvious question now. But I'm picking this one because you point out exactly the sort of situations that were causing me confusion, with multiple nested `using` statements that were not properly tabbed/indented and it made me feel unsure about the scope. Thanks! – Ryan Ries Oct 17 '13 at 14:36
  • If Visual Studio treated nested using statements fairly it would indent each one the same way it indents the others. But that would look really ugly. It's smart enough to prefer style and neatness instead. – Trevor Elliott Oct 17 '13 at 14:40
  • I instinctively like this, [although on reflection I guess I had a few additional thoughts](http://stackoverflow.com/a/22675224/618649). :-) – Craig Tullis Mar 26 '14 at 23:32
6

A using without braces means the using is in the scope of the next statement only - the same way the if condition works.

using (SecureString s = new SecureString())
    s.Foo(); // Works
s.Foo(); // out of scope

As a personal preference, I always include the braces, even for single statement if/using constructs, to avoid confusing situations like this.

Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
3

Then it is valid ony in the next command after the using statement.

Please note that it does not mean next line. Only next command.

Grzegorz W
  • 3,487
  • 1
  • 21
  • 21
2

The scope is essentially limited to the very next line.

using(var s = new SecureString())
    s.Whatever();
s.Whatever() // ERROR! s is out of scope

It's the same as using the if keyword with no brackets:

if(x == y)
    x = 4;
Dave Zych
  • 21,581
  • 7
  • 51
  • 66
2

With statements like using, if, and foreach, if you do not include brackets, the scope is simply the next statement (usually the next line). It's treated just like you included the brackets around that next statement. E.g.

if (someCondition)
    Console.WriteLine("someCondition is true!");
Console.WriteLine("I run regardless");
// same as
if (someCondition)
{
    Console.WriteLine("someCondition is true!");
}

using (var s = new SecureString())
    Console.WriteLine(s); // this works!
//Console.WriteLine(s); // s is no longer in scope, this won't compile
Tim S.
  • 55,448
  • 7
  • 96
  • 122
  • It's not so much that the braces are automatically added in; it's that the body of all of those constructs is always exactly one statement; curly braces allow you to treat multiple statements as a single statement. If you already have one statement then they simply aren't needed. It's not like the syntax specifically lists braces as optional. Those constructs simply say that they are followed by one statement, whatever that statement may be. – Servy Oct 17 '13 at 14:34
  • True, but I figured it made more sense to describe it the way I did, being the way people would normally think of it. – Tim S. Oct 17 '13 at 14:36
2

As everyone has answered this in that that you can essentially have an inline using statement that is equivelent to this:

using(var s = new SecureString()) s.Whatever();

However please don't do this as you will in my opinion make the code less readable and confuse other developers. I think this point is well made by the fact that you asked this question.

Ben Robinson
  • 21,601
  • 5
  • 62
  • 79
1

To expand on other answers:

using (SecureString s = new SecureString())
    // This statement is in using scope.

// This is not.
Jason Evans
  • 28,906
  • 14
  • 90
  • 154
  • If you're going to downvote, at least have the intelligence to comment on why my answer is worthy of a downvote. Otherwise how can I learn from my "wrong" answer? – Jason Evans Oct 17 '13 at 14:32
  • Further thoughts on how to clarify the intent of the code: http://stackoverflow.com/a/22675224/618649 – Craig Tullis Mar 26 '14 at 23:38
1

If you do not use brackets, only the next statement is valid

using (SecureString s = new SecureString())
    // statement here

If you want to include more than one statement, use brackets.

gleng
  • 6,185
  • 4
  • 21
  • 35
  • 2
    To be more precise, it's the next *statement* - which may span several lines, or even be on the previous line. And if the line consists of multiple statements, only the first statement would be within the `using` statement. – Jon Skeet Oct 17 '13 at 14:24
  • @JonSkeet You're absolutely right. I've updated my answer for clarity. – gleng Oct 17 '13 at 14:30
1

If there are no brackets, you just get one line. Same with "if" or "for" statements. For example:

for (int i = 0; i < 10; i++)
    Console.WriteLine(i.ToString());

if (str == "hello")
    Console.WriteLine("hello back!");

using (SecureString s = new SecureString())
    Console.WriteLine("Here we have s");

Console.WriteLine("but here it's out of scope already");
andrewpm
  • 534
  • 6
  • 12
0

using, just like for, while, if, else, and so many other keywords, always take exactly one statement as the "body" of the block.

If a programmer would like to execute multiple statements within the body they can use curly braces to create a complex statement, that is a single statement that executes multiple (or zero) statements. When you use curly braces after a using or if you're saying, "everything in here should be treated as one statement". If you already had exactly one statement to begin with there is no need to use braces to turn that into a single statement, so you can omit them.

Servy
  • 202,030
  • 26
  • 332
  • 449
0

Looking at a disassembly will show you exactly what is going on.

  static private void Function()
  {
     Console.WriteLine("before");

     using (SecureString s = new SecureString())
        s.Clear();

     Console.WriteLine("after");
  }

Using IL Dissassembler, the function above disassembles to the code below. You can see that the using statement is implemented with a try-finally wrapping the rest of the statement (which could be a block defined by curly braces, but in this case is just to the semicolon). The object you are using is disposed in the finally block. Then, outside the finally, the code continues with the next statement from the source.

.method private hidebysig static void  Function() cil managed
{
  // Code size       56 (0x38)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.Security.SecureString s,
           [1] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldstr      "before"
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  newobj     instance void [mscorlib]System.Security.SecureString::.ctor()
  IL_0011:  stloc.0
  .try
  {
    IL_0012:  ldloc.0
    IL_0013:  callvirt   instance void [mscorlib]System.Security.SecureString::Clear()
    IL_0018:  nop
    IL_0019:  leave.s    IL_002b
  }  // end .try
  finally
  {
    IL_001b:  ldloc.0
    IL_001c:  ldnull
    IL_001d:  ceq
    IL_001f:  stloc.1
    IL_0020:  ldloc.1
    IL_0021:  brtrue.s   IL_002a
    IL_0023:  ldloc.0
    IL_0024:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0029:  nop
    IL_002a:  endfinally
  }  // end handler
  IL_002b:  nop
  IL_002c:  ldstr      "after"
  IL_0031:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0036:  nop
  IL_0037:  ret
} // end of method Program::Function
jltrem
  • 12,124
  • 4
  • 40
  • 50
0

As mentioned in the other comments, when using the using statement the way you mentioned, it is only when you have one line.

I would like to add that in C# 8.0 you can use "using declarations" this way:

private void Function()
{
    // Some code here

    using SecureString s = new SecureString();

    // more code here
}

In this way, the lifetime of the using statement will extend to the end of the scope in which it is declared. The using locals will then be disposed in the reverse order in which they are declared.

Misha Zaslavsky
  • 8,414
  • 11
  • 70
  • 116