5 Good Practices for Error Handling in C#
Tags: csharp, dotnet, beginners, productivity
Published: 2022-03-16 15:26:00

The best way to prevent having bugs in your program or app is to avoid handling errors that could occur in your code. If you can avoid them, you won't have to check for them and handle them when they happen, right?

While that sounds good in theory, **it's not always possible to completely prevent errors from occurring;** otherwise you wouldn't have a program or app at all! When an error does occur and your program can't recover on its own, how you handle the error will depend on how much information the error provides about what caused it and where the problem occurred.

That is why I have decided to explain **5 simple and useful ways to handle errors in C#.**

---

## Understand what is error handling

First and foremost, **it is necessary to understand what error handling means**. The [term error handling](https://www.techopedia.com/definition/16626/error-handling) refers to a software application's reaction and recovery mechanisms in the event of an error. That is to say, it is a process that involves accurately **predicting**, **detecting**, and **resolving** errors in applications, programs, or communication.

Maintaining a program's regular execution flow is made easier via error handling. When it comes to error-handling approaches, many applications really encounter a slew of architectural issues.

🧠**Remember:** thrown errors are good.

---

## Always keep trace of the exception stack

Using `throw e;` is not a good way to throw a caught exception since C# allows us, simply with `throw;`, to throw the exception in a catch block.

This way we would keep track of the stack and get a much better view of the exception.

**Bad way:**

```csharp
try
{
    FunctionThatMightThrow();
}
catch (Exception ex)
{
    logger.LogInfo(ex);
    throw ex;
}
```

**Good way:**

```csharp
try
{
    FunctionThatMightThrow();
}
catch (Exception error)
{
    logger.LogInfo(error);
    throw;
}
```

Including information in an exception is a good practice since it will help in the debugging of the error. If, on the other hand, **the goal is to record an exception**, then throw should be used to pass the buck to a caller.

---

## Avoiding the use of "throw ex"

At first look, any developer could believe that `throw ex` is the best way to rethrow an exception after catching it. Yes, it is a simple way to do it, but not the right way to do it. **This option is not good because you would lose the stack trace**.

**Bad way:**

```csharp
try
{
    // Do something..
}
catch (Exception ex)
{
    // Any action something like roll-back or logging etc.
    throw ex;
}
```

**Good way:**

```csharp
try
{
    // Do something..
}
catch (Exception ex)
{
    // Any action something like roll-back or logging etc.
    throw;
}
```

We can see in the good way to do it I have simply used `throw`. In this way, **the original exception stack would be conserved**. Otherwise, with `throw ex`, it would be overwritten with the line of code where this statement was called.

---

## Avoid using if conditions

You should consider using numerous catch blocks for exception handling if you need to do different actions depending on the kind of exception. A bad practice is to use `if` conditional. 

**Bad way:**

```csharp
try
{
    // Do something..
}
catch (Exception ex)
{
    if (ex is TaskSchedulerException)
    {
        // Take action
    }
    else if (ex is TaskCanceledException)
    {
        // Take action
    }
}
```

**Good way:**

```csharp
try
{
    // Do something..
}
catch (TaskCanceledException ex)
{
    // Take action 
}
catch (TaskSchedulerException ex)
{
    // Take action
}
```

Even if we are creating numerous catch blocks, **it is always suggested to create a catch block** that includes the Exception argument as the final catch block. It provides as an auxiliary catch block.

---

## Always analyze the caught errors

If you catch an error, there's no point in ignoring it and letting it go because you won't have a chance to fix it or do anything about it.

It is always better, if you know an error might occur, to wrap that code in a try/catch.

**Bad way:**

```csharp
try
{
    FunctionThatMightThrow();
}
catch (Exception ex)
{
    // silent exception
}
```

**Good way:**

```csharp
try
{
    FunctionThatMightThrow();
}
catch (Exception error)
{
    NotifyUserOfError(error);
    // Another option
    ReportErrorToService(error);
}
```

As we can see, throwing the error is not a great solution because it might get lost in the console among all the printed stuff. By wrapping it in a try/catch, we can later (in case an error occurs there) create a plan or have a code path on how to handle it.

---

_These tips are adapted from [Clean Code Javascript](https://github.com/ryanmcdermott/clean-code-javascript). Thanks [Ryan McDermott](https://github.com/ryanmcdermott) for your great contribution!_