Best Practice for Exception Handling in a Windows Forms Application?

前端 未结 16 2002
滥情空心
滥情空心 2020-11-29 14:20

I\'m currently in the process of writing my first Windows Forms application. I\'ve read a few C# books now so I\'ve got a relatively good understanding of what language feat

相关标签:
16条回答
  • 2020-11-29 15:11

    Here are a few guidelines that I follow

    1. Fail-Fast: This is more of a exception generating guideline, For every assumption that you make and every parameter that you are getting into a function do a check to make sure that you're starting off with the right data and that the assumptions you're making are correct. Typical checks include, argument not null, argument in expected range etc.

    2. When rethrowing preserve stack trace - This simply translates to using throw when rethrowing instead of throw new Exception(). Alternatively if you feel that you can add more information then wrap the original exception as an inner exception. But if you're catching an exception only to log it then definitely use throw;

    3. Do not catch exceptions that you cannot handle, so don't worry about things like OutOfMemoryException because if they occur you won't be able to do much anyways.

    4. Do hook global exception handlers and make sure to log as much information as possible. For winforms hook both the appdomain and thread unhandled exception events.

    5. Performance should only be taken into consideration when you've analyzed the code and seen that it's causing a performance bottleneck, by default optimize for readability and design. So about your original question on the file existence check, I would say it depends, If you can do something about the file not being there, then yes do that check otherwise if all you're going to do is throw an exception if the file's not there then I don't see the point.

    6. There are definitely times when empty catch blocks are required, I think people who say otherwise have not worked on codebases that have evolved over several releases. But they should be commented and reviewed to make sure that they're really needed. The most typical example is developers using try/catch to convert string to integer instead of using ParseInt().

    7. If you expect the caller of your code to be able to handle error conditions then create custom exceptions that detail what the un excepected situation is and provide relevant information. Otherwise just stick to built-in exception types as much as possible.

    0 讨论(0)
  • 2020-11-29 15:13

    All of the advice posted here so far is good and worth heeding.

    One thing I'd like to expand on is your question "Do handling exceptions which might be thrown have a performance hit compared with pre-emptively testing things like whether a file on disk exists?"

    The naive rule of thumb is "try/catch blocks are expensive." That's not actually true. Trying isn't expensive. It's the catching, where the system has to create an Exception object and load it up with the stack trace, that's expensive. There are many cases in which the exception is, well, exceptional enough that it's perfectly fine to wrap the code in a try/catch block.

    For instance, if you're populating a Dictionary, this:

    try
    {
       dict.Add(key, value);
    }
    catch(KeyException)
    {
    }
    

    is often faster than doing this:

    if (!dict.ContainsKey(key))
    {
       dict.Add(key, value);
    }
    

    for every single item you're adding, because the exception only gets thrown when you are adding a duplicate key. (LINQ aggregate queries do this.)

    In the example you gave, I'd use try/catch almost without thinking. First, just because the file exists when you check for it doesn't mean that it's going to exist when you open it, so you should really handle the exception anyway.

    Second, and I think more importantly, unless your a) your process is opening thousands of files and b) the odds of a file it's trying to open not existing are not trivially low, the performance hit of creating the exception is not something you're ever going to notice. Generally speaking, when your program is trying to open a file, it's only trying to open one file. That's a case where writing safer code is almost certainly going to be better than writing the fastest possible code.

    0 讨论(0)
  • 2020-11-29 15:15

    There is an excellent code CodeProject article here. Here are a couple of highlights:

    • Plan for the worst*
    • Check it early
    • Don't trust external data
    • The only reliable devices are: the video, the mouse and keyboard.
    • Writes can fail, too
    • Code Safely
    • Don't throw new Exception()
    • Don't put important exception information on the Message field
    • Put a single catch (Exception ex) per thread
    • Generic Exceptions caught should be published
    • Log Exception.ToString(); never log only Exception.Message!
    • Don't catch (Exception) more than once per thread
    • Don't ever swallow exceptions
    • Cleanup code should be put in finally blocks
    • Use "using" everywhere
    • Don't return special values on error conditions
    • Don't use exceptions to indicate absence of a resource
    • Don't use exception handling as means of returning information from a method
    • Use exceptions for errors that should not be ignored
    • Don't clear the stack trace when re-throwing an exception
    • Avoid changing exceptions without adding semantic value
    • Exceptions should be marked [Serializable]
    • When in doubt, don't Assert, throw an Exception
    • Each exception class should have at least the three original constructors
    • Be careful when using the AppDomain.UnhandledException event
    • Don't reinvent the wheel
    • Don't use Unstructured Error Handling (VB.Net)
    0 讨论(0)
  • 2020-11-29 15:16

    You have to think about the user. The application crash is the last thing the user wants. Therefore any operation that can fail should have a try catch block at the ui level. It's not necessary to use try catch in every method, but every time the user does something it must be able to handle generic exceptions. That by no means frees you from checking everything to prevent exceptions in the first case, but there is no complex application without bugs and the OS can easily add unexpected problems, therefore you must anticipate the unexpected and make sure if a user wants to use one operation there won't be data loss because the app crashes. There is no need to ever let your app crash, if you catch exceptions it will never be in an indeterminate state and the user is ALWAYS inconvenienced by a crash. Even if the exception is at the top most level, not crashing means the user can quickly reproduce the exception or at least record the error message and therefore greatly help you to fix the problem. Certainly a lot more than getting a simple error message and then seeing only windows error dialog or something like that.

    That's why you must NEVER just be conceited and think your app has no bugs, that is not guaranteed. And it is a very small effort to wrap some try catch blocks about the appropriate code and show an error message / log the error.

    As a user, I certainly get seriously pissed whenever a brows or office app or whatever crashes. If the exception is so high that the app can't continue it's better to display that message and tell the user what to do (restart, fix some os settings, report the bug, etc.) than to simply crash and that's it.

    0 讨论(0)
  • 2020-11-29 15:17

    The golden rule that have tried to stick to is handle the exception as close to the source as possible.

    If you must re-throw an exception try to add to it, re-throwing a FileNotFoundException does not help much but throwing a ConfigurationFileNotFoundException will allow it to be captured and acted upon somewhere up the chain.

    Another rule I try to follow is not to use try/catch as a form of program flow, so I do verify files/connections, ensure objects have been initiated, ect.. prior to using them. Try/catch should be for Exceptions, things you can not control.

    As for an empty catch block, if you are doing anything of importance in the code that generated the exception you should re-throw the exception at a minimum. If there is no consequences of the code that threw the exception not running why did you write it in the first place.

    0 讨论(0)
  • 2020-11-29 15:18

    n my experience I've seen fit to catch exceptions when I know I'm going to be creating them. For instances when I'm in a web application and I'm doing a Response.Redirect, I know I'll be getting a System.ThreadAbortException. Since it's intentional I just have a catch for the specific type and just swallow it.

    try
    {
    /*Doing stuff that may cause an exception*/
    Response.Redirect("http:\\www.somewhereelse.com");
    }
    catch (ThreadAbortException tex){/*Ignore*/}
    catch (Exception ex){/*HandleException*/}
    
    0 讨论(0)
提交回复
热议问题