7 Exceptions
Download 251.07 Kb. Pdf ko'rish
|
7 Exceptions
- Bu sahifa navigatsiya:
- System errors
- Finally block
- Tip: other interview questions on this topic: ● "Is it possible to have multiple catch blocks after a try block
- How to ensure some piece of code will be called, even if an exception was thrown
7. How are exceptions handled in C#? Brief summary: Exceptions are handled by try-catch-finally blocks. Try contains code that may throw exceptions, catch defines what should be done if an exception of a given type is thrown, and finally is executed no matter if the exception was thrown or not. Every program may encounter some exceptional situations that need to be somehow handled. Let's take a look at some of them: ● System errors, like running out of memory - OutOfMemoryException is thrown ● Numeric errors, like when trying to increment an int that already has the maximum int value assigned - OverflowException is thrown ● Parsing errors, like trying to parse "hello" to an integer - FormatException is thrown ● Operation errors, like trying to remove the first element from an empty list - ArgumentOutOfRangeException is thrown Remember that in C# every exception type derives from class Exception. As developers, we are responsible for ensuring that all exceptions are properly handled in our application. Imagine that you want to use a calculator on your phone, and the application crashes every time you do something "illegal" like dividing by zero. It would be pretty annoying. It is much better to handle such a situation, by for example presenting the user some kind of error message that explains what is wrong. In C# we use try-catch-finally blocks to handle exceptions: ● In the try block, we put the code that may throw an exception ● In the catch block, we define what kind of exception we want to handle. If not specified, any kind of exception will be caught ● In the finally block we put code that needs to be executed no matter if the operation was successful or not Let's take a closer look at each of those blocks: ● Try block ○ Any code that we expect to possibly throw an exception should be put in the try block. But we can't expect everything. Exceptions are often, well, unexpected. For example, it's usually hard to predict OutOfMemoryException - it can happen almost anywhere. Or, for example, NullReferenceExceptions - it wouldn't make much sense to wrap every piece of code that uses objects that may be null in the try-catch blocks - that would cause terrible noise in the code. ○ The solution is to only use local try blocks when we truly expect some error-causing situations, and we can handle them in some specific way. All other cases should be handled by a global try-catch block. It is a try-catch block that wraps the entry point to the application (for example in the Main function in console applications), thus catching all exceptions that hadn't been caught in a more specific context. The downside of such a global try block is that it cannot be very specific - since it catches any type of an exception. Usually, such exceptions are only logged and presented to the user in some kind of error window. ● Catch block ○ Catch block defines what kind of exception will be handled, and how it will be done: ○ We can omit the exception variable name if we do not intend to use it: ○ We can also omit the exception type if we don't care about it and want to catch any type of exception: ○ We can have multiple catch blocks that handle different types of exceptions: ○ Please note that in the case of multiple catch blocks, when the exception is thrown it will be caught by the first catch block that handles the matching exception type. Because of that, we should always write catch blocks from the most specific to the most generic. Remember that the most generic type of exception is the Exception class, a base class for all other exceptions. Let's change the above code so the most generic exception is at the top: ○ As you can see, it does not compile. C# compiler is smart enough to know such code is incorrect. If it did compile, and if the "numbers" parameter would be null, such exception would be handled by the first, generic catch block. It is not what we want - we want to have specific behavior for NullReferenceException and for IndexOutOfRangeException. Always put more specific exceptions at the top, and more generic at the bottom of the catch blocks list. ● Finally block ○ The code in the finally block will always be executed, no matter if the exception was thrown in the try block or not. It is executed last, after the try block and any catch block, if an exception was thrown. It is used to clean up some resources that were used in the try block. For example, if you opened a database connection in the try block, you should close it in the finally block - to make sure it will be closed no matter if an exception was thrown. ○ You might think "Why close the database connection in the finally block if I can do it in the finalizer?". Technically, yes, but remember that we do not know when Garbage Collector will be fired and when it will execute finalizers. By cleaning resources in the finally block, we are ensuring it is done as soon as possible. It is especially important when the resources are limited - for example, a database may not allow more than one connection to be opened, and then it would be blocked until Garbage Collector would close the connection. Tip: other interview questions on this topic: ● "Is it possible to have multiple catch blocks after a try block?" Yes. You can catch any number of exceptions. It is important to first catch the more specific, and then more generic exceptions. ● "How to ensure some piece of code will be called, even if an exception was thrown?" You should put this code in the finally block. ● "What is the base type for all exceptions in C#?" System.Exception. Download 251.07 Kb. Do'stlaringiz bilan baham: |
Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling
ma'muriyatiga murojaat qiling