dcsimg
Results 1 to 9 of 9

Thread: How to keep nested using statements from making your code unreadable.

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Mar 2015
    Posts
    75

    How to keep nested using statements from making your code unreadable.

    Suppose you have some simple code like this:
    Code:
    //open connection
    OdbcConnection cnn = new OdbcConnection("connect string");
    cnn.Open();
    
    //load listbox 
    string sql = "SELECT Field1 FROM Table1";
    OdbcDataAdapter da = new OdbcDataAdapter(sql, cnn);
    DataSet ds = new DataSet();
    da.Fill(ds);
    foreach (DataRow dr in ds.Tables[0].Rows)
    {
         listBox1.Items.Add(dr["Field1"].ToString()) ;
    }
    
    //set label
    label.Text = "Hello World";

    If you add the using statement it quickly becomes a mess, and this is just a simple example.
    The problem to me is that the using statement forces you to create "artificial" blocks of code, instead of "logical" blocks.
    (not sure how to indent, this would be more clear with indenting)

    Code:
    //open connection
    using (OdbcConnection cnn = new OdbcConnection("connect string"))
    {
        cnn.Open();
    
        //load listbox 
        string sql = "SELECT Field1 FROM Table1";
        using (OdbcDataAdapter da = new OdbcDataAdapter(sql, cnn))
        {
            using (DataSet ds = new DataSet())
            {
                da.Fill(ds);
                foreach (DataRow dr in ds.Tables[0].Rows)
                {
                     listBox1.Items.Add(dr["Field1"].ToString()) ;
                }
    
            //set label
            label.Text = "Hello World";
            }
        }
    }

    Does anyone know of a good way to avoid this?

    Also I was wondering why you couldn't just add dispose statements at the end:

    Code:
    //open connection
    OdbcConnection cnn = new OdbcConnection("connect string");
    cnn.Open();
    
    //load listbox 
    string sql = "SELECT Field1 FROM Table1";
    OdbcDataAdapter da = new OdbcDataAdapter(sql, cnn);
    DataSet ds = new DataSet();
    da.Fill(ds);
    foreach (DataRow dr in ds.Tables[0].Rows)
    {
         listBox1.Items.Add(dr["Field1"].ToString()) ;
    }
    
    //set label
    label.Text = "Hello World";
    
    //dispose
    cnn.dispose();
    da.dispose();
    ds.dispose();
    Last edited by si_the_geek; Jun 12th, 2019 at 11:41 AM. Reason: added code tags

  2. #2
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,142

    Re: How to keep nested using statements from making your code unreadable.

    You can put multiple objects in one Using block by separating them with a comma, eg:
    Code:
        using (OdbcDataAdapter da = new OdbcDataAdapter(sql, cnn) , 
               DataSet ds = new DataSet())
        {
            ...
        }
    (I've added a line break for readability, but it isn't essential)

    Quote Originally Posted by madison320 View Post
    Also I was wondering why you couldn't just add dispose statements at the end:
    You can, but it isn't quite as safe... the Using block ensures that the dispose is run even if an exception is thrown.

    Writing your own equivalent usually takes more lines of code than the Using block.

    Quote Originally Posted by madison320 View Post
    (not sure how to indent, this would be more clear with indenting)
    Put the code inside code tags so it is displayed in a more readable way (including indenting), either using the # or VB buttons in the post editor screen (or at the top of the Quick Reply box), or by putting them in manually, like this: [code] code here [/code]

    I have added them to your post above.

  3. #3
    Frenzied Member PlausiblyDamp's Avatar
    Join Date
    Dec 2016
    Location
    Newport, UK
    Posts
    1,090

    Re: How to keep nested using statements from making your code unreadable.

    If you don't open the connection the DataAdapter will open and close it for you - that would remove the need to wrap the Connection in a using block. If you are leaving the DataAdapter to manage the connection for you then it will open it when needed and close it straight away, that would remove the need for you to explicitly manage the underlying connection yourself and you could avoid the need to dispose of the connection object.

    Also DataSets don't involve unmanaged memory so there is no real need to dispose of them either, they only have a Dispose method because they inherit MarshalByValueComponent which has a Dispose method.

    Saying that though you could also use the following
    Code:
             string sql = "SELECT Field1 FROM Table1";
                using (OdbcConnection cnn = new OdbcConnection("connect string"))
                using (OdbcDataAdapter da = new OdbcDataAdapter(sql, cnn))
                using (DataSet ds = new DataSet())
                {
                    cnn.Open();
                    da.Fill(ds);
                    foreach (DataRow dr in ds.Tables[0].Rows)
                    {
                        listBox1.Items.Add(dr["Field1"].ToString());
                    }
    
                    //set label
                    label.Text = "Hello World";
                }
    to simplify things.

    The problem with just putting the calls to .Dispose at the end is what happens if an unhandled exception occurs - the .Dispose calls won't happen and you could start to keep unmanaged resources hanging around a lot longer than you expect.

  4. #4

    Thread Starter
    Lively Member
    Join Date
    Mar 2015
    Posts
    75

    Re: How to keep nested using statements from making your code unreadable.

    Quote Originally Posted by PlausiblyDamp View Post
    If you don't open the connection the DataAdapter will open and close it for you - that would remove the need to wrap the Connection in a using block. If you are leaving the DataAdapter to manage the connection for you then it will open it when needed and close it straight away, that would remove the need for you to explicitly manage the underlying connection yourself and you could avoid the need to dispose of the connection object.

    Also DataSets don't involve unmanaged memory so there is no real need to dispose of them either, they only have a Dispose method because they inherit MarshalByValueComponent which has a Dispose method.

    Saying that though you could also use the following
    Code:
             string sql = "SELECT Field1 FROM Table1";
                using (OdbcConnection cnn = new OdbcConnection("connect string"))
                using (OdbcDataAdapter da = new OdbcDataAdapter(sql, cnn))
                using (DataSet ds = new DataSet())
                {
                    cnn.Open();
                    da.Fill(ds);
                    foreach (DataRow dr in ds.Tables[0].Rows)
                    {
                        listBox1.Items.Add(dr["Field1"].ToString());
                    }
    
                    //set label
                    label.Text = "Hello World";
                }
    to simplify things.

    The problem with just putting the calls to .Dispose at the end is what happens if an unhandled exception occurs - the .Dispose calls won't happen and you could start to keep unmanaged resources hanging around a lot longer than you expect.
    That's a lot better than nesting the using statements.

    The only thing I didn't like was that you have to move the string sql = "SELECT Field1 FROM Table1" line up above the using statements but maybe that's not a big deal.

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Mar 2015
    Posts
    75

    Re: How to keep nested using statements from making your code unreadable.

    Quote Originally Posted by si_the_geek View Post
    You can put multiple objects in one Using block by separating them with a comma, eg:
    Code:
        using (OdbcDataAdapter da = new OdbcDataAdapter(sql, cnn) , 
               DataSet ds = new DataSet())
        {
            ...
        }
    (I've added a line break for readability, but it isn't essential)

    You can, but it isn't quite as safe... the Using block ensures that the dispose is run even if an exception is thrown.

    Writing your own equivalent usually takes more lines of code than the Using block.



    Put the code inside code tags so it is displayed in a more readable way (including indenting), either using the # or VB buttons in the post editor screen (or at the top of the Quick Reply box), or by putting them in manually, like this: [code] code here [/code]

    I have added them to your post above.
    If there's an exception, wouldn't your program crash and stop running and never get to the Finally block?

  6. #6
    Frenzied Member PlausiblyDamp's Avatar
    Join Date
    Dec 2016
    Location
    Newport, UK
    Posts
    1,090

    Re: How to keep nested using statements from making your code unreadable.

    Quote Originally Posted by madison320 View Post
    If there's an exception, wouldn't your program crash and stop running and never get to the Finally block?
    It would if there were no catch blocks anywhere, if however this code was in a method that had an unhandled exception but a method further up the call stack caught the exception then the application wouldn't crash.

  7. #7

    Thread Starter
    Lively Member
    Join Date
    Mar 2015
    Posts
    75

    Re: How to keep nested using statements from making your code unreadable.

    Quote Originally Posted by PlausiblyDamp View Post
    If you don't open the connection the DataAdapter will open and close it for you - that would remove the need to wrap the Connection in a using block. If you are leaving the DataAdapter to manage the connection for you then it will open it when needed and close it straight away, that would remove the need for you to explicitly manage the underlying connection yourself and you could avoid the need to dispose of the connection object.

    Also DataSets don't involve unmanaged memory so there is no real need to dispose of them either, they only have a Dispose method because they inherit MarshalByValueComponent which has a Dispose method.

    Saying that though you could also use the following
    Code:
             string sql = "SELECT Field1 FROM Table1";
                using (OdbcConnection cnn = new OdbcConnection("connect string"))
                using (OdbcDataAdapter da = new OdbcDataAdapter(sql, cnn))
                using (DataSet ds = new DataSet())
                {
                    cnn.Open();
                    da.Fill(ds);
                    foreach (DataRow dr in ds.Tables[0].Rows)
                    {
                        listBox1.Items.Add(dr["Field1"].ToString());
                    }
    
                    //set label
                    label.Text = "Hello World";
                }
    to simplify things.

    The problem with just putting the calls to .Dispose at the end is what happens if an unhandled exception occurs - the .Dispose calls won't happen and you could start to keep unmanaged resources hanging around a lot longer than you expect.
    I wish I could do something like this:

    Code:
    static void foo()
    {
        using (someobject object1 = new someobject(x)
        using (someobject object2 = new someobject(y)
        using (someobject object3 = new someobject(z)
        {
    
            do whatever;
    
        }
    }
    Then it would almost be like declaring variables at the top of your function. The problem is that you have to instantiate in the using() and sometimes that requires code before the using statement which kinda messes it up. Maybe if I do some sort of "dummy" instantiation during the using, then I could use object1, object2, object3 normally the rest of the way.

  8. #8
    Frenzied Member PlausiblyDamp's Avatar
    Join Date
    Dec 2016
    Location
    Newport, UK
    Posts
    1,090

    Re: How to keep nested using statements from making your code unreadable.

    Personally I don't have a big issue with code before the using statements, then again I tend to declare variables closer to where I need them rather than always at the top of the module anyway.

    I suspect if you tried to do a "dummy" instantiation in the using and then really instantiated them later on you would probably end up with an increased chance of not correctly disposing of the resources and I doubt it would make the code easier to read either.

  9. #9
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    34,046

    Re: How to keep nested using statements from making your code unreadable.

    This strikes me as being a matter of personal taste. Once it was indented, I felt that the second snippet in your original post was easier to read than the first snippet, which you appear to prefer. I suppose it isn't really of any value to note that my taste differs from yours, but you might consider the point. Over the years, my style of coding has changed slowly and steadily. If I were to look back at code I wrote in the 90s, I'd recognize some of the conventions that are still around, remember some of the conventions that I have since abandoned, and generally not like the look of the code all that much. So, I rather expect tastes to change. Perhaps yours will, too.
    My usual boring signature: Nothing

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width