Search  
Always will be ready notify the world about expectations as easy as possible: job change page
Articles
Jan 22

5 exception handling secrets In .NET — Junior to Senior

5 exception handling secrets In .NET — Junior to Senior
Author:
Source:
Views:
1849

The Software Interview Question that you should be aware of!

Exception handling is a crucial aspect of software development that allows you to manage and recover from unexpected or exceptional situations that can occur during program execution. These exceptional situations are typically errors or unforeseen conditions that disrupt the normal flow of a program. Exception handling helps improve the robustness and reliability of your code by providing a structured way to deal with such situations.

You know me, I like to get straight to the point, so place your booty in a comfortable position, and Let’s Get Right Into It!

Exception Handling

All of the examples will be in the context of .NET. Keep in mind, however, that exceptions are existing for every single language and it will be very beneficial for any programmer to be acquainted with as many details as possible.

In C#, as we mentioned, there are four main keywords used for exception handling:

  1. try: This keyword marks a block of code where you expect exceptions to occur. It encloses the code that might cause an exception. If an exception occurs within the try block, the runtime will immediately jump to the appropriate catch block (if available) to handle the exception.
  2. catch: The catch block follows the try block and specifies how to handle different types of exceptions. It contains code that is executed when an exception of a particular type is thrown within the associated try block. You can have multiple catch blocks to handle different types of exceptions.
  3. finally: The finally block is used to contain code that needs to be executed regardless of whether an exception was thrown or not. It is often used for cleanup operations such as closing files or releasing resources. The code in the finally block will execute even if there is a return statement in the try or catch block, or if an exception is not caught.
  4. throw: The throw keyword is used to explicitly raise an exception. You can throw both built-in and custom exceptions. Throwing an exception allows you to signal that an error or exceptional condition has occurred and provides information about the problem.

Exception Mastery

You knowing how to use the blocks, mentioned above will be enough to be able to answer the interview question.

I however love to go in details. Below I will give examples of bad and good error handling. Let’s take a look:

1 — Use specific exception types:

Bad Example:

try
{
    // Some code that may throw an exception
}
catch (Exception ex)
{
    // Catching the base Exception type
    Console.WriteLine("An error occurred: " + ex.Message);
}

Improved Example:

try
{
    // Some code that may throw a specific exception
}
catch (FileNotFoundException ex)
{
    Console.WriteLine("File not found: " + ex.FileName);
}
catch (IOException ex)
{
    Console.WriteLine("Input/output error: " + ex.Message);
}

Why?

You should be wary about which exception you catch. Not only because you have to resolve them in different ways, depending on the exception. But also because it will help you with logging.

2 — Catch only what you can handle:

Bad Example:

try
{
    // Some code that may throw an exception
}
catch (Exception ex)
{
    // Suppressing the exception without proper handling
    // This can lead to hidden bugs and make debugging difficult
}

Improved Example:

try
{
    // Some code that may throw an exception
}
catch (SpecificException ex)
{
    // Handle the specific exception appropriately
    Console.WriteLine("An error occurred: " + ex.Message);
}

Why?

Let’s say that you are working with some web sockets. You can’t forsee all of the problems that can happen. However, you can foresee a few. Those that we know we can handle, should be handled.

3 — Log exceptions:

Bad Example:

try
{
    // Some code that may throw an exception
}
catch (Exception ex)
{
    // No logging of the exception
    Console.WriteLine("An error occurred: " + ex.Message);
}

Improved Example:

try
{
    // Some code that may throw an exception
}
catch (Exception ex)
{
    // Log the exception for diagnosis
    Logger.Log(ex);
    Console.WriteLine("An error occurred. Please contact support.");
}

Why?

When working with clients, the problems that can happen are very hard to detect. You should always log when you have the chance. This will help you understand the problem when it comes back. Otherwise, you will be building extended loggings and just waste time.

If you are worried that it will make the file huge, just place a special debug flag that will log only when a specific value is found in your application. This way the user can “enable” the logs when he stumble upon a problem.

4 — Keep catch blocks short:

Bad Example:

try
{
    // Some code that may throw an exception
}
catch (Exception ex)
{
    // Complex logic within the catch block
    if (ex is SomeSpecificException)
    {
        // Handle specific case
    }
    else if (ex is AnotherSpecificException)
    {
        // Handle another case
    }
}

Improved Example:

try
{
    // Some code that may throw an exception
}
catch (SomeSpecificException ex)
{
    // Handle specific case
}
catch (AnotherSpecificException ex)
{
    // Handle another case
}

Why?

This one is depending on the problems that are encountered. An engineer might not be able to always keep the blocks short, but it will definitely be better for reading later on!

5 — Use finally for cleanup:

Bad Example:

FileStream fileStream = null;
try
{
    fileStream = new FileStream("file.txt", FileMode.Open);
    // Some code that may throw an exception
}
catch (Exception ex)
{
    Console.WriteLine("An error occurred: " + ex.Message);
}
finally
{
    // Cleanup code mixed with exception handling
    if (fileStream != null)
    {
        fileStream.Close();
    }
}

Improved Example:

try
{
    using (FileStream fileStream = new FileStream("file.txt", FileMode.Open))
    {
        // Some code that may throw an exception
    }
}
catch (Exception ex)
{
    Console.WriteLine("An error occurred: " + ex.Message);
}

Why?

While the primary purpose of the finally block is indeed for code cleanup and ensuring that certain actions are taken regardless of whether an exception occurred or not, there are a few other scenarios where you might consider using the finally block:

  1. Resource Management: Apart from direct cleanup, you might use the finally block for resource management that goes beyond immediate cleanup. For instance, you might use it to release a lock or unlock a resource that should be held for as short a time as possible.
  2. Logging or Metrics: You might use the finally block to log information or record metrics about the execution of a block of code. This can provide useful diagnostic information even if an exception is thrown.
  3. State Restoration: In some cases, you might want to restore the application’s state or some variables to a consistent state before exiting a method, regardless of whether an exception occurred. This could be especially relevant in complex algorithms or long-running processes.
  4. Special Cases Handling: In certain cases, you might want to handle special cases that don’t directly involve cleaning up resources. For example, you might display a message to the user or send a notification when an exceptional situation arises.
  5. Conditional Logic: While it’s generally best to keep finally blocks focused on cleanup, there might be cases where you use them for conditional logic based on the outcome of the try or catch blocks. However, this approach can make your code less readable and more difficult to maintain.

Remember, the primary role of the finally block is to ensure that certain actions are always taken, regardless of whether an exception occurred. If your use of the finally block extends beyond this purpose, it's important to ensure that your code remains clear, maintainable, and logically organized. If you find that your finally block is becoming too complex or performing actions that are unrelated to cleanup, you might want to reconsider your design and consider refactoring your code to achieve better separation of concerns.

Outro

I hope you found this article useful. I had tons of fun writing it.

Thank you for being with me and I will see you in the next one! Bye!

Similar
Aug 8
Author: Anton Martyniuk
Integration testing is a type of software testing essential for validating the interactions between different components of an application, ensuring they work together as expected. The main goal of integration testing is to identify any issues that may arise when...
Oct 27, 2022
Author: Sebastian Streng
Writing code can be very exciting but it also can be very frustrating if your code is based on nested loops. Iterations are still one the most important parts of coding. So how can we avoid using ugly nested loops...
May 30
Author: Erik Pourali
Imagine crafting a library app where users effortlessly find books by title, author, or genre. Traditional search methods drown you in code. But fear not! Dynamic Querying in C# saves the day. In our tale, crafting separate search methods for...
Apr 16, 2022
Author: Mohsen Saniee
Today, developers are paying more attention to mapping libraries than ever before, because modern architecture forces them to map object to object across layers. For example, in the past I prepared a repository for clean architecture in github. So it’s...
Send message
Type
Email
Your name
*Message