29

Since the C# using statement is just a syntactic sugar for try/finally{dispose}, why does it accept multiple objects only if they are of the same type?

I don't get it since all they need to be is IDisposable. If all of them implement IDisposable it should be fine, but it isn't.

Specifically I am used to writing

using (var cmd = new SqlCommand())
{
    using (cmd.Connection)
    {
        // Code
    }
}

which I compact into:

using (var cmd = new SqlCommand())
using (cmd.Connection)
{
    // Code
}

And I would like to compact furthermore into:

using(var cmd = new SqlCommand(), var con = cmd.Connection)
{
    // Code
}

but I can't. I could probably, some would say, write:

using((var cmd = new SqlCommand()).Connection)
{
    // Code
}

since all I need to dispose is the connection and not the command but that's besides the point.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Andrei Rînea
  • 20,288
  • 17
  • 117
  • 166
  • 2
    Am I learning something new here? What's with the second, non-assigned using statement in the top example? Does that item become the scope? – spender Jun 08 '09 at 17:57
  • @spender: the argument of using needs to be an expression that can be converted to IDisposable. A declaration is (just one) such an expression. – H H Jun 08 '09 at 18:06
  • @spender: Yes, you (probably) learned something new. The syntax of using is using(IDisposableInstance) statement;. Just as Henk Holterman said an assignment is an operation whose result (often unused but here used) is the value assigned. – Andrei Rînea Jun 08 '09 at 18:12
  • In the end I think I will just use the stacked version (the 2nd one presented in the question).. :( – Andrei Rînea Jun 08 '09 at 18:32
  • 1
    Inspired by your question I tried the following idea: http://stackoverflow.com/questions/974484/captured-variable-instantiating-problem/ – VVS Jun 10 '09 at 12:18
  • @spender (Jun 8 17:57) : Well, I may sound corny/cheesy but if the question helped you in any way including learning something I might ask for an upvote? :D – Andrei Rînea Jul 14 '09 at 13:19
  • The syntax they offer is close enough – Casebash Feb 19 '10 at 02:55
  • I think this is actually a good idea. I would think it's just something that simply hasn't been implemented yet. I'd be surprised if there's an actual specific reason why this doesn't exist. I could be wrong though... – BFree Jun 08 '09 at 17:57

4 Answers4

21

You can do this though:

using (IDisposable cmd = new SqlCommand(), con = (cmd as SqlCommand).Connection)
{
   var command = (cmd as SqlCommand);
   var connection = (con as SqlConnection);
   //code
}

Perhaps that would be satisfactory to you.

Joseph
  • 25,330
  • 8
  • 76
  • 125
  • This is the closest workaround I've seen so far. However I'll need to cast the cmd back to SqlCommand in the block in order to manipulate it. The same with "con" which I'll have to open in order to do my job. – Andrei Rînea Jun 08 '09 at 18:13
  • @Andrei You're right, I'll update my answer to reflect what you're talking about. – Joseph Jun 08 '09 at 18:13
  • Which is exactly what I menat. I don't consider this an improvement over the using() using () { } version – H H Jun 08 '09 at 18:17
  • Yeah, if you have to cast the stuff back later, it's absolutely worse than just putting it on two lines. – mqp Jun 08 '09 at 18:18
  • 1
    @Henk Oh I understand. I agree. I prefer to use the stacked usings myself as well. I was just giving an answer to his question of how you could do what he was trying to do. – Joseph Jun 08 '09 at 18:22
  • @Joseph, obviously this is a horrible technique as you have acknowledged, but it is certainly an ingenious piece of code to come up with! – RichardOD Jun 08 '09 at 18:27
17

There's no particularly good technical reason; we could have come up with a syntax that allowed multiple declarations of nonhomogeneous types. Given that we did not, and there already is a perfectly good, clear, understandable and fairly concise mechanism for declaring nested using blocks of different types, we're unlikely to add a new syntactic sugar just to save a few keystrokes.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
5

Other variable declarations in C# only allow you to declare multiple variables of the same type in the same statement; I don't see why using headers should be different.

mqp
  • 70,359
  • 14
  • 95
  • 123
  • Yes and no. There's nothing stopping you from doing : IComparable c1, c2; and then later in your code have c1 and c2 be totally different concrete types that implement IComparable. That's what the OP is pointing out, all they need to be is IDisposable... – BFree Jun 08 '09 at 17:58
  • Sure, but you can do it in a using statement too with IDisposable, for example, this is legal: using (IDisposable a = new SqlCommand(), b = new SqlConnection()) – mqp Jun 08 '09 at 18:01
  • BFree, that's exactly what mquander is saying, isn't it? using (IDisposable x = new Connection(), y = new Command()) would work but is rather useless. The type of the reference counts. – H H Jun 08 '09 at 18:03
0

My personal way of using this might fit the bill:

private const string SQL_CONNECTION = "Your Connection String Here";

private void Test(string sqlCmd)
{
  using (var cmd = new SqlCommand(sqlCmd, new SqlConnection(SQL_CONNECTION)))
  {
    cmd.Connection.Open();
    cmd.ExecuteNonQuery();
    cmd.Connection.Close();
    // Close() is not really necessary.
    // Dispose will Close the connection.
  }
}

No, this is not two instances of the using clause in one line, but it is as compact as you are trying to get in your example.

What's more, you can make this even more compact and programmer friendly by turning your connection string into a Private Property:

private SqlConnection OpenConnection
{
  get {
    var con = new SqlConnection(SQL_CONNECTION);
    con.Open();
    return con;
  }
}

Now, that first bit of code above in Test() could be shortened to the following:

private void Test2(string sqlCmd)
{
  using (var cmd = new SqlCommand(sqlCmd, OpenConnection))
  {
    cmd.ExecuteNonQuery();
  }
}

That makes coding very nice.