Nested Using Statements


I got a comment on the language feature post, asking about an easier way to write:


  using (StreamWriter w1 = File.CreateText(“W1”))
  {
      using (StreamWriter w2 = File.CreateText(“W2”))
      {
          // code here
      }
   }


You can do this by writing:


  using (StreamWriter w1 = File.CreateText(“W1”))
  using (StreamWriter w2 = File.CreateText(“W2”))
  {
      // code here
  }

Comments (19)

  1. John Rusk says:

    Eric,

    Can’t you also do this:

    using (StreamWriter w1 = File.CreateText("W1"), w2 = File.CreateText("W2"))

    {

    }

    (If, and only if, both objects are of the same type).

    Incidently, why is this syntax supported, but restricted to cases where both have the same type?

  2. Neil Cowburn says:

    That’s cool, but I prefer the first way for several reasons.

    Firstly, it’s easier to read the first snippet. Also, the first snippet clearly defines the context of each using statement, whereas the second could lead to ambiguity for someone who is not familiar with this syntax.

  3. real programmers just expand the whole thing out with a huge monolithic sequence of try finallys.

    (I’m kidding. Really.)

  4. Daniel O'Connell says:

    John: I can’t tell you why the syntax was decided in this way, however I can explain why it works that way.

    The grammar for using is defined as:

    using-statement:

    using ( resource-acquisition ) embedded-statement

    resource-acquisition:

    local-variable-declaration

    expression

    A local-variable-declaration is the same syntax you use to declare variables, with the same rules applied

    int x;

    double y,z;

    Thus, the using statement can have multiple variables of the same type just as a variable declaration can.

    Mixing types makes for more difficult grammar, consider situations where you want to do int x, y; and double a,b;

    the equivilent using statement would be

    using (int x, y, double a, b)

    which is strange and unheard of in the rest of the language.

  5. John Rusk says:

    Thanks Daniel.

    >the equivilent using statement would be

    >using (int x, y, double a, b)

    I guess I’m wondering why something like this is not supported:

    using (int x, y; double a, b)

    (I just changed one of your commas to a semi-colon.)

    Presumably because it doesn’t really offer much benefit (other than a bit more brevity) over the solution Eric originally posted.

  6. Jason Kemp says:

    Thanks for the post, Eric. I think I learn something new every day reading blogs. And I wouldn’t have learned about this if I didn’t ask. I think I like that syntax better than I was suggesting in the language post, and what John Rusk is asking here. With our suggestion one could write something like this:

    using( ResourceA a = …;

    ResourceB b = ….;

    ResourceC c = …;

    etc.

    ){

    //do stuff

    }

    which hampers readability. With the current syntax you can see right away every one of them. Too bad I haven’t seen any code examples like this.

  7. Isnt the syntax Eric proposing just your usual drop of the curly brace for implicit one-line function??? If so, whats the big deal, and (more importantly) how is that an improvement? There’s now the usual danger inherent in implicit scoping (and the usual trade-off of brevity vs. clarity).

  8. I’ve always wondered why the language designers wanted ‘using’ to work like a control-flow statement (like while, if, etc.), because it doesn’t control any flow.

    I would have liked it better as a declaration specifier like this:

    using StreamWriter out = File.CreateText(…);

    which would inject the name ‘out’ in the current scope instead of opening a new one.

    I guess that’s just the C++ programmer in me talking… Which reminds me that the new C++/CLI will soon have this feature anyway so I won’t complain about C# not having it :).

  9. Matthew W. Jackson says:

    Eric, you’ve made my day. I didn’t realize that was possible, although it makes perfect sense in the context of C-style languages.

    I even like how Visual Studio is nice enough not to indent the nested using block like it normally would for other blocks (like if or for).

    Now if somebody could just tell me how to get a delegate pointing to a get or set accessor of a property in C# (without post-compile IL hacks) in a type-safe manner (meaning reflection is a no-no)… It’s a shame the C# compiler always gives an error when using the get_PropertyName and set_PropertyName methods directly.

  10. Nested using statements can soak up a lot of indentation so Eric Gunnerson has posted a tip on how to code them more succinctly. Taking his example, instead of this: using (StreamWriter w1 = File.CreateText("W1")) { using (StreamWriter w2 =…

  11. Sean Schade says:

    This is great! It’s a lot easier to read than indented using statement.

    Thanks,

    Sean

    …more discussion

    http://blog.magenic.com/seans/archive/2004/08/06/261.aspx

  12. Jonathan Pryor says:

    RE: Pointing a delegate to a property…

    I don’t think this is possible, primarily due to the language grammar. As you mentioned, the C# compiler doesn’t like you referring to the underlying get_ and set_ methods, primarly because these methods are marked as "special" (I forget the actual IL opcodes; it’s probably specialname or something).

    Since you can’t refer to the methods directly, you’d have to directly use the Property. Alas, in the C# language grammar merely referencing a Property is identical to invoking the get_ function.

    For example, with methods:

    // this works

    MyDelegate d = new MyDelegate (this.MyMethod);

    // this doesn’t; MyMethod() is invoked.

    MyDelegate e = new MyDelegate (this.MyMethod());

    A property reference outside of assignment context implicitly invokes the get_ method, so:

    // error; similar to previous method example

    MyDelegate f = new MyDelegate (this.Property);

    // above implicitly identical to non-C# code:

    MyDelegate g = new MyDelegate (this.get_Property());

    So, what do you do? In C# 1.1, you add a helper method which can be used by the Delegate.

    In C# 2.0, you could use an anonymous delegate:

    // C# 2.0: getter

    MyDelegate h = delegate {return this.Property;};

    // C# 2.0: setter

    MyDelegate i = delegate (int value) {this.Property = value;};

    It’s still not ideal, but at least there’s less typing.

    – Jon

  13. Matthew W. Jackson says:

    Just a side note, I’ve added a link to Jonathan’s comment from my feedback request FDBK13230 (regarding property delegates) on MSDN. In hindsight I should have added it as a proposed solution, but I’m still getting used to using their feedback site, and it doesn’t really agree with my browser half the time.

    http://lab.msdn.microsoft.com/ProductFeedback/viewFeedback.aspx?FeedbackId=e9496dee-5fab-41eb-882c-247898daa19d

  14. Adam Meltzer says:

    While yes, this does work, it’s generally considered bad programming practice in the sense of readability to not use braces in these instances.

  15. Daniel O'Connell says:

    John: No that syntax won’t work, mainly because of the definition of local-variable-declaration, but there are semantic issues as well. By allowing an arbitrary number of semicolons I imagine the resource-acquisition section would get confusing quickly since one could do

    using(X x = Mymethod(); Y y = AnotherExpression; Q q = v; V r = 7;)

    which is really more of a block, I think.

    Stéphane: I implemented such a feature experimentally in mono at one point. It worked but the average lifespan of an object would go up a bit and it made varaible declaration a bit messy(variables had to be declared all through the body, even if they didn’t make sense to). Also, since there was no clear way to know when to create a copy of the value, the variables were effectivly read-only. Because they were read only there was no easy way to create a variable and then assign to it conditionally. It convinced me that the using statement was probably a better choice, its at the least less surprising.

  16. Dave Goldstein says:

    re: why not have using decorate variables…

    I have been asking for this for a year.

    Why not have a using on a variable declaration, which promotes the IDispose behavior to the enclosing scope – and if it’s called something other than "using" that’s fine ;^)

    public void SomeMethod() {

    using IDbConnection conn = GetDbConnection();

    // …

    }

    …yeah, a name like "disposable" would fit better too…