7 Exceptions


Download 251.07 Kb.
Pdf ko'rish
Sana14.11.2023
Hajmi251.07 Kb.
#1773431
Bog'liq
7 Exceptions



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