The problem with Try Catch Finally...

Discussion in 'ASP .Net' started by VB Programmer, Aug 12, 2003.

  1. Variable scope doesn't make sense to me when it comes to Try Catch Finally.

    Example: In order to close/dispose a db connection you have to dim the
    connection outside of the Try Catch Finally block. But, I prefer to dim them
    "on the fly" only if needed (save as much resources as possible). A little
    further... I may wish to create a sqlcommand and datareader object ONLY if
    certain conditions are met. But, if I want to clean these up in the Finally
    then I am FORCED to declare them above the Try.

    Why???
     
    VB Programmer, Aug 12, 2003
    #1
    1. Advertisements

  2. VB Programmer

    Jeff Voigt Guest

    Why not declare them and just CREATE them when you need to. After all,
    that's what may take the longest.

    - Jeff
     
    Jeff Voigt, Aug 12, 2003
    #2
    1. Advertisements

  3. Well, you are most of the way there in your description. Variables are local
    to the scope they are declared in, and scope is determined by code block.
    Any time you have a code block, you can declare local variables in that
    block. This is true for try - catch - finally, if, while, or anything other
    similar construct. This enables you to declare a new variable inside that
    block, and have it marked for GC once you exit that code block.

    What it means for you in terms of your try - catch is that you need to code
    around how you create it. First of all, declaring a variable doesn't
    allocate space for it, so you don't have to worry about that. You may also
    want to re-think what you are enclosing in a try-catch block. You don't need
    to wrap huge chuck of code in such a block - you just need to wrap a
    dangerous operation that might throw an exception in such a block. So,
    declare, prepare, then when you execute the risky operation, wrap it in a
    try-catch. I seldom have more than a couple of lines of code in a try block,
    and usually have exactly one.
     
    Chris Jackson, Aug 12, 2003
    #3
  4. You mentioned "I seldom have more than a couple of lines of code in a try
    always

    No, that is not the standard. I, for example, will put all of the code in a
    method inside a try/catch block, and then put additional try/catch blocks
    and conditional code inside that outer block to catch specific errors. The
    outside one is for anything I might have missed. How you use it is up to
    you, and what your needs are.
    That's a difficult question to answer (which is why I wrap all of my method
    code in an outer try/catch block). Any operation which might cause your
    program to malfunction is risky.

    The bottom line is (and everyone here seems to agree on this), declare your
    variables outside of the block, and assign them inside the block.

    --
    HTH,

    Kevin Spencer
    Microsoft MVP
    ..Net Developer
    http://www.takempis.com
    Complex things are made up of
    lots of simple things.
     
    Kevin Spencer, Aug 12, 2003
    #4
  5. And one other thing I should mention, in case you don't understand. The
    problem you experienced was due to referencing variables declared inside the
    try/catch block from the Finally block. The Finally block executes
    regardless of whether an error occurs or not. That means that it must be
    able to access the variables used in it regardless of whether they were
    assigned or not. When you declare a variable inside the try block, your code
    might never reach the declaration before execution falls through to the
    catch block. Therefore, any variable referenced in the Finnally block must
    be declared prior to the Try block.

    --
    HTH,

    Kevin Spencer
    Microsoft MVP
    ..Net Developer
    http://www.takempis.com
    Complex things are made up of
    lots of simple things.
     
    Kevin Spencer, Aug 12, 2003
    #5
  6. VB Programmer

    Terry Burns Guest

    Folks, I cant beleive how long this thread has become !

    When we are old and grey, we can enchant our grandchildren with stories of
    how we spent our precious youth talking about Try Catch blocks !

    Sorry, couldnt resist that, keep smiling :)
     
    Terry Burns, Aug 12, 2003
    #6
  7. Good stuff! :)

     
    VB Programmer, Aug 12, 2003
    #7
  8. You mentioned "I seldom have more than a couple of lines of code in a
    try
    I would never go so far as to put all of the code inside of a method inside
    of a try-catch block, because then you are never really sure what you are
    catching. Sure, you could simply catch a System.Exception, but if you don't
    know what you're catching, and as a result can't react appropriately, you
    probably don't want to just sit on that error instead of passing it up
    through the call stack.

    With VB6, you just had to universally set up an onerror statement that
    caught all errors, and then go through and figure out what happened and what
    to do about it. The beauty of try-catch is that you can wrap specific
    statements and handle it appropriately.

    Let's do an example - open up a SQL Server connection, set up a command
    object, and execute that command object:

    ----
    SqlConnection connMyConnection = new SqlConnection(szConnectionString);
    SqlCommand cmdMyCommand = new SqlCommand("MyCommand", connMyConnection);
    cmdMyCommand .CommandType = CommandType.StoredProcedure;
    cmdMyCommand .Parameters.Add("@myParameter", SqlDbType.VarChar, 50).Value =
    szValue;
    connMyConnection.Open();
    cmdMyCommand.ExecuteNonQuery();
    ----

    The SqlConnection constructor that I used does not throw an exception, so
    there is nothing to catch there.
    The SqlCommand constructor that I used does not throw an exception, so there
    is nothing to catch there.
    Setting the command type could throw an ArgumentException, so you'll want to
    catch that.
    The add method of the parameters collection doesn't throw an exception, nor
    does the Value property of the SqlParameter object, so there is nothing to
    catch there.
    The Open method of SqlConnection could throw either an
    InvalidOperationException or a SqlException, so you'll want to catch that.
    The ExecuteNonQuery method of SqlCommand could throw a SqlException, so
    you'll want to catch that.

    So, you end up with:

    ----
    SqlConnection connMyConnection = new SqlConnection(connectionString);
    SqlCommand cmdMyCommand = new SqlCommand("MyCommand", connMyConnection);
    try {
    cmdMyCommand .CommandType = CommandType.StoredProcedure;
    } catch (ArgumentException myArgumentException) {
    // do something to react to this - since it's hard coded, you can
    probably fix your code and get rid of this check
    } finally {
    // do some cleanup work
    }
    cmdMyCommand .Parameters.Add("@myParameter", SqlDbType.VarChar, 50).Value =
    szValue;
    try {
    connMyConnection.Open();
    } catch (InvalidOperationException myInvalidOperationException) {
    // do something to react to this - since it's hard coded, again you can
    probably fix your code and dispense with this check
    } catch (SqlException mySqlException1) {
    // do something to react to this - either dump to the event log or, if
    in debug mode (use preprocessors) write back the message
    } finally {
    // do some cleanup work
    }
    try {
    cmdMyCommand.ExecuteNonQuery();
    } catch (SqlException mySqlException2) {
    // do something to react to this - either dump to the event log or, if
    in debug mode (use preprocessors) write back the message
    } finally {
    // do some cleanup work
    }
    ----

    If you look up the best practices, you will find it stated in as many words:

    "Use try/finally blocks around code that can potentially generate an
    exception and centralize your catch statements in one location. In this way,
    the try statement generates the exception, the finally statement closes or
    deallocates resources, and the catch statement handles the exception from a
    central location."

    Full list of best practices here:

    http://msdn.microsoft.com/library/d...l/cpconbestpracticesforhandlingexceptions.asp

    So yes, I would beg to differ. I do consider this a standard. It's what I've
    been doing in C++ for years now.

    Also, you can check for exceptions before they are thrown. If you are going
    to close the aforementioned SqlConnection, instead of just using:

    connMyConnection.Close();

    use:

    if (connMyConnection != null && connMyConnection.State !=
    ConnectionState.Closed) {
    connMyConnection.Close();
    }

    And so it goes.


    --
    Chris Jackson
    Software Engineer
    Microsoft MVP - Windows XP
    Windows XP Associate Expert
    --
     
    Chris Jackson, Aug 12, 2003
    #8
  9. VB Programmer

    Michael Lang Guest

    A risky operation is anything that could raise an exception. When calling a
    method check the help on it. It will list any exceptions that it raised and
    the conditions to cause the exception.

    Anytime a risky operation is called place it in the try block, and in the
    finally block clean up any resources such as filestreams, database
    connections, references to COM objects, etc... In the catch block you
    could...

    1) propagate the error to the caller
    2) wrap that error in a new custom (InnerException) error of your own giving
    a more human understandable message and throw to caller
    3) log the error and continue with rest of method
    4) ignore and do again (entire try-catch-finally in a loop).
    5) ignore the error and continue with rest of method.
    6) ?? anything you desire

    What you do depends on the needs/requirements of your application.
     
    Michael Lang, Aug 12, 2003
    #9
  10. I would never go so far as to put all of the code inside of a method
    inside
    I'm always sure of what I'm catching, because I use a global error-handler
    routine in my outer try/catch block, which logs the Exception message, any
    InnerException message, and a Stack trace to the Event Log. This is so that
    I can figure out what caused the error and determine how to best handle it
    with code.

    --
    HTH,

    Kevin Spencer
    Microsoft MVP
    ..Net Developer
    http://www.takempis.com
    Complex things are made up of
    lots of simple things.
     
    Kevin Spencer, Aug 12, 2003
    #10
  11. I'm always sure of what I'm catching, because I use a global error-handler
    I am sure this works just fine, and I am not attempting to disparage what
    you are doing. But I think this is an example of "extending" the syntax of
    try-catch to more closely approximate the behavior of OnErrorGoto from
    Visual Basic. While this is certainly creative and effective, I wouldn't
    consider it to be a best practice, that's all. You are writing code to
    figure out what the error is (presumably using reflection) and react
    appropriately. But the beauty of structured exception handling is that you
    no longer have to do that, and while you may have templates in place for
    creating your applications, somebody who is new to the construct would be
    best served by learning the optimal use of said construct.

    --
    Chris Jackson
    Software Engineer
    Microsoft MVP - Windows XP
    Windows XP Associate Expert
    --
     
    Chris Jackson, Aug 12, 2003
    #11
  12. You totally misunderstand my usage of Try/Catch. If you will review my
    original message, you will see that I employ the outer Try/Catch as a means
    of catching anything I've missed in the other error-handling code I put into
    my code. It is a way of catching things I haven't thought of, so that I can
    fix them with proper error-handling. And Reflection has nothing to do with
    it, unless you consider a Stack Trace some form of Reflection.

    In the real world, one doesn't have the time to spend to make software
    perfect. One has to compromise. If I had all the time in the world, I could
    write the perfect software, and it would never misbehave. However, even
    Microsoft, with all of it's money and resources, doesn't have the time or
    the budget to write perfect software. My outer Try/Catch is a means of
    identifying problems that are not identified (and may not manifest
    themselves in an easily-identifiable manner) so that they can be fixed.
    Microsoft has implemented mechanisms, such as Error Reporting, to identify
    problems so that they can be fixed as well.

    I find it odd that you don't (1) understand what I'm doing, and (2) assume
    that, because it is not standard according to your philosophy, it is not a
    "Best Practice." Best Practices are developed by people with a lot of hard
    experience, and philosophizing about software doesn't create them.
    Experience does.

    I can tell you this: I write a lot of robust, pretty-well-optimized
    software. It does what it is intended to do, with a very small percentage of
    failure. Regardless of the characterization that you may put upon my
    practices, I think that whether or not they achieve that goal is the best
    measure of them.

    --
    HTH,

    Kevin Spencer
    Microsoft MVP
    ..Net Developer
    http://www.takempis.com
    Complex things are made up of
    lots of simple things.
     
    Kevin Spencer, Aug 12, 2003
    #12
  13. What do you do when the method changes, adding new exceptions?
     
    John Saunders, Aug 13, 2003
    #13
  14. VB Programmer

    JohnG Guest

    Both of you are right.
    With the structure exception handling, we need do as Chris does. But with
    the other unhandle expection, we need to do it in the outer most procedure,
    may not within the same function.


     
    JohnG, Aug 13, 2003
    #14
  15. You totally misunderstand my usage of Try/Catch. If you will review my
    I don't believe that I misunderstand it at all. In fact, I believe I
    acknowledged that I am sure it is both creative and effective. What you are
    doing is, objectively, emulating a VB6- construct. There is nothing wrong
    with that - it worked for quite a few versions of VB and VBScript. That
    doesn't make it structured exception handling, but it does make it yet
    another tool in your tool belt.
    Absolutely. You simply take a different approach. After having worked with
    the framework a long time, most of what I do I have seen before. I wrap the
    calls I know throw exceptions, and handle them gracefully. You wrap the
    whole thing and handle them concurrently. Both solve the problem of trapping
    exceptions - one is a more structured way to do it. We aren't all going to
    use the same techniques. I obviously think mine is better, because that is
    what I choose to use. You obviously disagree, hence your choice.
    I was imprecise with my language, so let me clear this up. The original
    question was one of whether or not this was a standard. You asserted that it
    certainly was not. I asserted that it was, and then provided a link to the
    standard itself. I find that to be, at a minimum, compelling. However, as a
    technique that works for you, it certainly is a best practice, so forgive
    the sloppiness of my writing. It is a best practice, but it is not a
    standard.
    Absolutely, and I certainly don't want to disparage what you are doing, as I
    said before. There are all kinds of standards out there, and there are
    plenty of people who break the rules.

    I think it behooves everybody to know the rules, so they can decide
    knowingly when it is appropriate to break them. I see it as the difference
    between spending a year reading Wrox books and spending a year getting a
    Masters degree in computer science at an ivy league school. The guy who gets
    the degree in computer science may not have the practical tips and tricks
    down yet, but knowing the fundamentals they are more likely to become an
    amazing programmer, whereas the person who only reads the practical how-to's
    without understanding the fundamentals is destined to never be more than a
    good programmer. But, with as many bad programmers as there are in the
    world, I'm willing to settle for good. However, I think it's worthwhile to
    struggle for great.

    --
    Chris Jackson
    Software Engineer
    Microsoft MVP - Windows XP
    Windows XP Associate Expert
    --
     
    Chris Jackson, Aug 13, 2003
    #15
  16. VB Programmer

    Michael Lang Guest

    Usually a given method only has one or two exceptions that is can raise to
    the caller. That method may change how it is implemented in the future, but
    it usually won't change the types of exceptions that it raises. If it did,
    I would consider that breaking compatibility. Any compatibility changes
    should be well documented in a changelog for the new version. If the
    functionality of the object changes that much you should review your code
    anyway.

    For example, the indexer (Item property) on a Collection will never raise
    more than an "ArguementOutOfRangeException", no matter how the
    implementation changes. What other logical error can possibly happen?
    Don't include things like memory related exceptions as those can occur at
    any point in any code.

    The most important thing to keep in mind about exceptions is that objects
    that use resources and require disposal should be disposed of in a finally
    clause. Once you allocate the resource, the rest of the code until the
    disposal should be enclosed in a try block, and the disposal in the finally
    clause. It doesn't matter what the exception is, just dispose of the
    resource.

    The second purpose of exceptions would be to control your program flow as in
    one of the (5+) I mentioned earlier. (Although you should use other ways to
    control program flow if available, since exceptions are expensive.) If you
    don't know what the exception is (because it is new to the current version)
    then you wouldn't have been able to use it to control program flow using the
    previous version. Thus the first time it is logged, you'll realize you have
    a new type of exception to handle logically.
     
    Michael Lang, Aug 13, 2003
    #16
  17. Man, this is beginning to get boring.

    1. There is a significant difference between Standards and what you refer to
    as Standards. Standards are created by organizations such as ISO and ANSI.
    The document you pointed to
    (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/ht
    ml/cpconbestpracticesforhandlingexceptions.asp) is hardly a standard. It is
    an article in the MSDN Library. I have written articles for MSDN as well,
    including a "Best Practices" article regarding ASP development. These are
    hardly Standards by any stretch of the imagination. They are the thoughts,
    experiences, and opinions of individual developers who have had a lot of
    experience in the technology they write about. Standards are developed over
    a long period of time by a large number of people working in concert.

    2. You will note that in my original message I said "No" to the question of
    whether the practice you described was a Standard. Note that I didn't say
    there was anything wrong with it, just that it is not a Standard. It is not.
    There is no Standard. I then gave an example of a different method for
    handling some errors (which I employ in most of the software I write, due to
    the nature of that software), and that started this whole mess. Apparently
    you misread my remark as some advocacy of some sort for one technique over
    another. I was simply opening possibilities for this person. I am the last
    person to advocate following anyone, or restricting creativity. It is
    creativity and the loosening of restrictions that fosters innovation and
    invention.

    2. NOTHING in the article you mentioned contradicts my technique. In fact, I
    use ALL of the techniques mentioned in the article in my development. Take
    another look, and tell me where the article states that putting an outer
    Try/Catch block around a method is wrong. I took a good long look, and it
    ain't there.

    3. I could count the number of VB6 projects I have done on one hand, and
    have fingers left over.

    4. I think it behooves everyone to know the difference between rules and
    opinions. I know altogether too many "monkey see monkey do" developers out
    there, and they're pretty lousy at it for the most part. Nothing new is ever
    discovered by following the leader. Especially when you reach the point
    where you ARE a leader and you realize that these guys aren't gods; they're
    just people like you.

    5. I think that both reading books and spending a year getting a Masters
    degree fall into the same category, and neither of them will make someone a
    good developer. I buy about 2 books a year, which I use to "get my feet wet"
    in a new technology, after which I rely almost exclusively upon SDKs and
    other authoritative reference material, as well as experimentation and
    research among a wide variety of sources, mostly on the Internet. Reading
    books and going to school will only make a student as good as their teacher.
    Hardly the sort of thing to make one an expert. Remember that school
    teachers don't make the big bucks. So how good can they be at what they
    teach? If they were good enough to make the big bucks they would. I believe
    that is where we get the old saying "Those who can do; those who can't
    teach." They make a good starting point, but I would argue that anyone who
    stays in school long enough to get a Masters degree is likely a slow
    learner.

    6. My philosophy about what makes a good developer is one who works hard to
    understand all of the tools and technologies avilable, and understands the
    principles involved. Principles are much more useful than methodologies, as
    methodologies are limited, and principles can be applied in creative and
    innovative ways. It is the difference between Newton and Einstein. Laws are
    useful to a point, but principles are much more powerful, and open up
    possibilities that haven't been explored by those who restrict themselves to
    what has been done before. Of course, it is much easier to simply follow;
    the paths have already been cleared. But I am not willing to settle for
    good. The Great beckons to me, and while I may never achieve it, the effort
    alone makes the trip worthwhile.

    7. An open mind is a teachable mind.

    --
    HTH,

    Kevin Spencer
    Microsoft MVP
    ..Net Developer
    http://www.takempis.com
    Neither a follower nor a lender be.
     
    Kevin Spencer, Aug 13, 2003
    #17
  18. VB Programmer

    Michael Lang Guest

    I don't think I disagree with you? I think we have a communication gap.

    If a new exception type is thrown with a new version of an assembly you use,
    then your code that depended on the previous version is going to break.
    Your choice is if your code will crash, or you'll be using the wrong logic.

    For example:
    =========================================================================
    void MyMethod()
    {
    //simple variable declarations/ initializations.
    DangerousClass _myInstance = new DangerousClass()
    try
    {
    ... code using _myInstance that could cause exception
    }
    catch (SpecializedDocumentedException exSpec)
    {
    ... handle special error type ...
    }
    catch (Exception exGeneric)
    {
    ... your standard logging of potentially new exceptions ...
    throw new ApplicationException("Unknown exception in MyClass.",
    exGeneric);
    // pass this up to client since you don't know the effects of such
    an undiscovered exception type.
    // i wouldn't recommend continuing on without knowing the effects of
    an unknown exception.
    }
    finally
    {
    _myInstance.Dispose(); //or other cleanup logic related to
    DangerousClass
    }
    }
    =========================================================================

    Does this make a little more sense? Of coarse it gets more complicated if
    you have more than one "dangerous" type. In the case where the second type
    uses the first, you may end up with multiple nested try-catch-finally
    blocks. Such as...
    =========================================================================
    void MyMethod2()
    {
    //simple variable declarations/ initializations.
    DangerousClass _myInstance = new DangerousClass()
    DangerousClass2 _myInstance2; //uses "DangerousClass"
    try
    {
    _myInstance2 = new DangerousClass2(_myInstance)
    .. can use _myInstance here ...
    try
    {
    .. can also use _myInstance here ...
    ... use _myInstance2 here
    }
    catch (SpecializedDocumentedException2 exSpec2) //only catch
    exception by "DangerousClass2"
    {
    ...handle special error type ...
    }
    finally
    {
    _myInstance2.Dispose(); //or other cleanup logic related to
    DangerousClass2
    }
    }
    catch (SpecializedDocumentedException exSpec) //exception raised by
    "DangerousClass"
    {
    ... handle special error type ...
    }
    catch (Exception exGeneric)
    {
    ... your standard logging of potentially new exceptions ...
    throw new ApplicationException("Unknown exception in MyClass.",
    exGeneric);
    // pass this up to client since you don't know the effects of such
    an undiscovered exception type.
    // i wouldn't recommend continuing on without knowing the effects of
    an unknown exception.
    }
    finally
    {
    _myInstance.Dispose(); //or other cleanup logic related to
    DangerousClass
    }
    }
    =========================================================================

    Of coarse they don't have to be nested such as:
    =========================================================================
    void MyMethod3()
    {
    //simple variable declarations/ initializations.
    DangerousClass _myInstance = new DangerousClass()
    DangerousClass2 _myInstance2 = new DangerousClass2()
    //both classes independant in this example...
    try
    {
    ... code using either "dangerous" class type that could cause
    exception
    }
    catch (SpecializedDocumentedException exSpec) //exception type raised by
    "DangerousClass"
    {
    ... handle special error type ...
    }
    catch (SpecializedDocumentedException2 exSpec2) //exception type raised
    by "DangerousClass2"
    {
    ... handle special error type ...
    }
    catch (KnownCommonException exComm) //can be thrown by either type of
    class
    {
    ... handle known generic error here ...
    }
    catch (Exception exGeneric)
    {
    ... your standard logging of potentially new exceptions ...
    throw new ApplicationException("Unknown exception in MyClass.",
    exGeneric);
    // pass this up to client since you don't know the effects of such
    an undiscovered exception type.
    // i wouldn't recommend continuing on without knowing the effects of
    an unknown exception.
    }
    finally
    {
    _myInstance.Dispose(); //or other cleanup logic related to
    DangerousClass
    }
    }
    =========================================================================

    This is only a small sample. I couldn't comment on your situation without
    knowing more about it. There is no single way to handle exceptions.

    The key is that you usually handle all unknown exception types in the same
    way. I pass them up to the client ulitmately. The user should ultimately
    see these types of critical unrecognized exceptions. This does not mean the
    app will crash. In the UI, place a try block around the entire contents of
    methods. The catch block should display the error in a message box. Such
    as:
    =========================================================================
    public class MyForm{
    public void SomeMethod(...)
    {
    ... declare types here ... no init of complex types.
    try
    {
    .. all work here ...
    }
    catch (KnownExceptionType exK)
    {
    ... display custom user friendly message with problem ...
    ... IE. "File does not exist", "Network Connection lost.", etc...
    }
    catch (Exception ex)
    {
    MessageBox.Show(this, ex.ToString());
    // displays entire exception stack modally to this current form
    // user to be instructed to report these bugs,
    // or use automated report system like Microsoft.
    }
    }//end method
    }//end form
    =========================================================================

    I hope this helps.
     
    Michael Lang, Aug 13, 2003
    #18
  19. logic.

    No, Michael, your choice is to write code that won't break, to begin with.
    Don't write code whose correctness depends on an exception being thrown. For
    instance, it makes sense to catch a specific exception (which means catching
    its derived classes if it's not sealed) and doing something different in
    control flow, or doing something special with properties of the exception.
    But it should not be the case that your program will function incorrectly or
    in an unknown manner if some new exception should happen to be thrown.

    At some point in the future, C# and VB.NET may gain something like a
    "throws" clause in Java. That would allow the kind of programming where you
    actually _depend_ on the set of exceptions which could be thrown. In this
    case, the program wouldn't compile if called methods began returning new
    exception types, and your code would have to catch every exception type
    which can be thrown.

    Until then, there is, as far as I know, no contract between the developer of
    a class library and its users, stating that the set of exceptions will not
    change. This implies that your code has to be able to deal with any such
    changes.

    ....
    I agree that _someone_ should see them, but whether the user should see them
    depends on the user. I do things like display "Can't insert new data - maybe
    this is a duplicate?" if I get one of the exceptions which can result from
    that, otherwise "Can't insert new data". In both cases, the full exception
    is logged.
     
    John Saunders, Aug 13, 2003
    #19
  20. Chad, could you shed some light on the issue? Provide a URL to an article,
    perhaps?
     
    John Saunders, Aug 13, 2003
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.