Advertisement
Поиск  
Always will be ready notify the world about expectations as easy as possible: job change page
Jan 1, 2023

Creating Custom C# Exception Types

Автор:
Matt Eland
Источник:
Просмотров:
1355

New and old ways of creating your own exceptions in dotnet with C# 11 and .NET 7.

Let’s talk about building custom exceptions in C# code and why you’d want to do that. We’ll cover the traditional way as well as a newer way you might want to do this using the required keyword in C# 11.

Exception management in dotnet is quite versatile by default with try / catch / throw capabilities and a diverse set of built-in exceptions. Sure people tend to make some common mistakes in exception management, but these are easily learned with proper mentoring.

But sometimes the existing exceptions aren’t enough. Sometimes you want to create your own custom C# Exceptions.

Some reasons you might want to create a custom exception in C#:

  • No built-in exception adequately matches your situation
  • You need to track custom properties on an exception object
  • You want to make sure no existing catch block catches your exception accidentally.

In these cases you would want to create your own C# exception. Let’s take a look at how this works.

Creating a Custom C# Exception using Constructors

Custom C# exceptions are just classes that happen to inherit from some Exception object.

Given that, the following is a very simple exception:

public class SimpleException : Exception
{
}

Note: it is our convention in dotnet to end exception names with the word Exception.

This SimpleException could then be thrown with the following code:

throw new SimpleException();

This exception could then be caught by a catch (SimpleException ex) block in a try / catch block.

However, this Exception object is so simple that it’s not practically helpful.

Instead, let’s look at a slightly more complex exception:

public class OverdraftException : InvalidOperationException
{
   public OverdraftException(decimal startingBalance, decimal withdrawAmount)
     : base($"Attempted to overdraft the account. The staring balance was {startingBalance:C} and the amount withdrawn was {withdrawAmount:C}")
   {
      StartingBalance = startingBalance;
      WithdrawAmount = withdrawAmount;
   }
   public decimal StartingBalance { get; }
   public decimal WithdrawAmount { get; }
}

This class is a bit more involved.

First of all, the OverdraftException inherits from InvalidOperationException instead of the base Exception. This is an optional step, but it would allow you to catch the OverdraftException in either a catch (OverdraftException ex) or Catch (InvalidOperationException ex) block. This also tells us a bit more about the nature or circumstances of the exception.

Second, OverdraftException has two custom properties that are set in its constructor. This allows us to access additional data in our catch block for logging or resolving the error.

Third, note that OverdraftException has a single constructor that takes in the startingBalance and withdrawAmount parameters. This constructor then builds a custom message and passes that message on to the InvalidOperationException base constructor.

This means that the only way to throw this exception is as follows:

throw new OverdraftException(1000, 5000);

The benefit of this is that we now have a very accurate and consistent overdraft message on the exception object. Additionally, the exception will contain the StartIngBalance and WithdrawAmount properties that we can use in our error handling:

catch (OverdraftException ex)
{
   Console.WriteLine($"Starting Balance: {ex.StartingBalance:C}");
   Console.WriteLine($" Withdraw Amount: {ex.WithdrawAmount:C}");
}

This makes it a lot easier to respond to your own custom C# exceptions and get the data you need to handle them.

Creating a Custom C# Exception with C# 11

Given how the C# programming language has matured, I wanted to show a second example using the required keyword and bypassing providing a custom constructor entirely.

Consider the following custom C# exception written in C# 11 on .NET 7:

public class OverdraftException : InvalidOperationException
{
    public required decimal Balance { get; init; }
    public required decimal WithdrawAmount { get; init; }
    public override string Message => $"This is an overdraft. Withdrew ${WithdrawAmount} with balance of ${Balance}";
}

This class is considerably more concise, and arguably more readable.

It uses the required and init keywords to declare a pair of properties that must be provided during object initialization as follows:

throw new OverdraftException()
{
    Balance = 1000,
    WithdrawAmount = 5000
};

Given the required keyword, these properties cannot be omitted.

The class also overrides the Message property with its own custom message. This allows it to retain the same behavior as the previous version via customizing the Message and effectively making it a derived or calculated property.

Final Thoughts

Both of these ways of declaring and throwing custom C# exceptions work, so you and your team will need to decide which you like better.

In many projects you may not need to use custom C# exceptions at all, but when you need them they can be extremely handy.

Personally, I’ve benefitted greatly from custom C# exceptions with a light bit of inheritance. This allowed me to catch exceptions relevant to only my application and know I’d have the relevant data I needed every time I caught them.

Use them or ignore them, custom C# exceptions are one of many tools available to you on your journey to building quality software in dotnet.

Похожее
Mar 12, 2023
Author: Ibrahim Jaber
Introduction: In today’s world, real-time communication is essential for many web applications. For example, consider an online game where players need to communicate with each other in real-time, or a chat application where users expect instant messaging. Fortunately, SignalR, a...
Apr 5
Author: Dayanand Thombare
IntroductionCaching is a technique used to store frequently accessed data in a fast-access storage layer to improve application performance and reduce the load on backend systems. By serving data from the cache, we can avoid expensive database queries or API...
Aug 24, 2022
Author: Jaydeep Patil
In this article, we will learn about global exception handling implementation using .NET Core 6 Web API step-by-step.Agenda Introduction Implementation of Global Exception HandlingPrerequisites Visual Studio 2022 .NET...
Mar 18
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 each...
Написать сообщение
Почта
Имя
*Сообщение


© 1999–2024 WebDynamics
1980–... Sergey Drozdov
Area of interests: .NET Framework | .NET Core | C# | ASP.NET | Windows Forms | WPF | HTML5 | CSS3 | jQuery | AJAX | Angular | React | MS SQL Server | Transact-SQL | ADO.NET | Entity Framework | IIS | OOP | OOA | OOD | WCF | WPF | MSMQ | MVC | MVP | MVVM | Design Patterns | Enterprise Architecture | Scrum | Kanban