14
Clean Code in C# Part 5 Exception Handling
When Developing applications errors may occur. Sometimes you are trying to open a file, but the file is opened by another program. Maybe you are trying to call an external API but the service is down. For most of these cases exception handling is the best approach to manipulate errors that may occur.
Error that occurs in C# can raise an exception. The Exception object has information about the error, this interface could easily replace the need of error codes in the application. If an exception is not handled in C# the program terminates. Consider the code written in .NET 6 bellow:
Example 1:
string filePath = null;
File.Open(filePath, FileMode.Open);
System.ArgumentNullException HResult=0x80004003
Message=Path cannot be null. (Parameter 'path')
Source=System.Private.CoreLib
StackTrace: at
System.IO.Strategies.FileStreamHelpers.ValidateArguments(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
at System.IO.File.Open(String path, FileMode mode)
at Program.$(String[] args) in C:\Users\Caio Sousa\Program.cs:line 4
The information of Example 1 contains data provided by the exception object. We can observe a default message, the type of the exception in this case it was ArgumentNullException. The method called and the path of the program.
Uncle bob suggests using exceptions instead of returning error codes. This sense since C# has many types of Exceptions supported in its robust library in the Microsoft Exception Class Documentation.
Example 2:
try
{
string filePath = null;
File.Open(filePath, FileMode.Open);
}
catch (ArgumentException)
{
Console.WriteLine("The informed parameter is invalid.");
}
finally
{
//Dispose resources
}
To handle exceptions in C# the try, catch keywords are used between the code that need to be verified. Examples 2 displays how to catch the argument exception from Example 1. In .NET 6 all exception types Inherits the system.Exception base class. Notice that there is also a finally keyword being used. The finally section will run if an exceptions occurs or not.
When working with exceptions it is wise to give meaning to the exceptions. Analyze the code bellow:
Example 3:
string filePath = null;
try
{
File.Open(filePath, FileMode.Open);
}
catch (ArgumentNullException)
{
Console.WriteLine("The informed parameter is null, please try again.");
}
catch (ArgumentException)
{
Console.WriteLine($"The parameter: {filePath} is invalid, please try again.");
}
The ArgumentNullException class inherits the ArgumentException class, therefore in Example 2 the ArgumentException catches the ArgumentNullException. In C# the System.Exception base class catches all types of Exceptions.
Regarding Example 3, we now have different information for when a filepath is null or the filepath is invalid. The detail of information can help developers that need to maintain the code in case errors occurs.
When handling exceptions it is possible to catch multiple types of exceptions. This type of exception handling can increase the size of methods and sometimes it might not as clean as it could. Uncle bob suggests wrapping exceptions in other classes and handling errors with a common known exception object. Specially when working with third party libraries. In C# one can create custom exception classes that must inherit from the System.Exception base class.
Careful with null values, passing null values and returning null values, can be misleading and cause unwanted errors in application. One can use the throw keyword to raise an exception. When developing .NET application the ArgumentNullException can be used to throw exceptions regarding unwanted null values.
Avoid continuing program logic inside catch statement.
Well developed software should always consider a good exception handling strategy. Error handling needs to be considered when developing applications in C# for robust and maintainable software.
- Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin.
- Programing in C# by Wouter de Kort
- https://docs.microsoft.com/en-us/dotnet/api/system.exception
14