Drani Academy – Interview Question, Search Job, Tuitorials, Cheat Sheet, Project, eBook

C#.Net

Tutorials – C#.Net

 
Chapter 7: Exception Handling


Chapter 7 of our C# tutorial focuses on exception handling. Exception handling is a critical aspect of software development, allowing you to gracefully handle unexpected situations and errors. In this chapter, we’ll explore the basics of exceptions, how to handle them effectively, and best practices for robust error management in C#.

7.1 Introduction to Exceptions

In any software application, errors and unexpected situations can occur. These errors may be caused by factors such as invalid input, network issues, file not found, or division by zero. To ensure that your application remains stable and doesn’t crash when these errors occur, C# provides a mechanism called “exception handling.”

An exception is an event that occurs during the execution of a program and disrupts the normal flow of instructions. When an exception is thrown, it’s said to be “raised,” and the program flow jumps to a special block of code called an “exception handler.”

7.2 The Exception Hierarchy

C# has a rich hierarchy of exception classes that provide detailed information about different types of errors. At the root of this hierarchy is the System.Exception class. All other exception classes in C# inherit from this base class.

Some common exception classes include:

  • System.Exception: The base class for all exceptions.
  • System.SystemException: The base class for system exceptions.
  • System.ApplicationException: The base class for application exceptions.
  • System.ArgumentException: Thrown when an argument is not valid.
  • System.DividedByZeroException: Thrown when division by zero is attempted.
  • System.NullReferenceException: Thrown when attempting to access a null object.
  • System.IO.IOException: Thrown for file and I/O-related errors.
  • System.Net.WebException: Thrown for network-related errors.

Understanding the exception hierarchy helps you choose the appropriate exception type for specific error scenarios.

7.3 Throwing Exceptions

In C#, you can explicitly throw exceptions to indicate that an error or exceptional condition has occurred in your code. To throw an exception, you use the throw keyword, followed by an exception object.

Here’s an example of how to throw a custom exception:

public int Divide(int dividend, int divisor)
{
if (divisor == 0) {
throw new DivideByZeroException("Cannot divide by zero."); }
return dividend / divisor; }

 

In this example, if the divisor is zero, a DivideByZeroException is thrown. You can also throw custom exceptions by creating your own exception classes that inherit from System.Exception.

7.4 Catching Exceptions

Catching exceptions is the process of handling and responding to exceptions that have been thrown. You catch exceptions using try-catch blocks. The try block contains the code that might raise an exception, while the catch block handles the exception if one is thrown.

Here’s a basic example:

try
{
int result = Divide(10, 0); // This will throw a DivideByZeroException Console.WriteLine("Result: " + result); // This line won't be executed }
catch (DivideByZeroException ex) { Console.WriteLine("An error occurred: " + ex.Message); }

In this example, the try block calls the Divide method with a divisor of 0, which raises a DivideByZeroException. The exception is caught in the catch block, and an error message is displayed.

7.5 Multiple catch Blocks

You can have multiple catch blocks to handle different types of exceptions. The first catch block that matches the exception type will be executed. If none of the catch blocks match, the exception propagates up the call stack.

try
{
int result = Divide(10, 0); Console.WriteLine("Result: " + result); }
catch (DivideByZeroException ex) { Console.WriteLine("Divide by zero error: " + ex.Message); }
catch (ArgumentException ex) { Console.WriteLine("Invalid argument: " + ex.Message); }
catch (Exception ex) { Console.WriteLine("An error occurred: " + ex.Message); }

In this example, the Divide method throws a DivideByZeroException, which is caught by the first catch block. If a different exception were thrown, such as an ArgumentException, it would be caught by the corresponding catch block.

7.6 The finally Block

The finally block is used to specify code that should be executed regardless of whether an exception is thrown or not. This is often used to ensure that certain resources are cleaned up, such as closing files or database connections.

FileStream file = null;
try { file = File.Open("file.txt", FileMode.Open);
// Perform operations on the file }
catch (IOException ex) { Console.WriteLine("An error occurred: " + ex.Message); }
finally {
if (file != null) { file.Close(); } }

In this example, the finally block ensures that the file is closed, even if an exception occurs in the try block.

7.7 Custom Exceptions

While C# provides a wide range of built-in exceptions, you can create your own custom exception classes when you need to handle specific errors in your application. To create a custom exception, you typically create a new class that inherits from System.Exception or one of its subclasses.

Here’s an example of a custom exception class:

public class MyCustomException : Exception
{
public MyCustomException() { }
public MyCustomException(string message) : base(message) { }
public MyCustomException(string message, Exception innerException) : base(message, innerException) { } }

 

You can then throw and catch instances of your custom exception just like built-in exceptions.

7.8 Rethrowing Exceptions

Sometimes, you may want to catch an exception, perform some handling, and then rethrow the exception to let it propagate to the calling code. You can rethrow an exception using the throw statement without an exception object.

try
{
// Code that may throw an exception }
catch (Exception ex) {
// Handle the exception Console.WriteLine("An error occurred: " + ex.Message);
// Rethrow the exception
throw; }

 

Rethrowing an exception is useful when you want to log or report an error but still allow the exception to be handled at a higher level.

7.9 Best Practices for Exception Handling

Effective exception handling is crucial for robust software. Here are some best practices to consider:

  1. Catch Specific Exceptions: Catch only the exceptions you can handle. Avoid catching the base System.Exception unless it’s at the highest level of your application.

  2. Log Exceptions: Always log exceptions to record what went wrong. Include relevant information like the exception type, message, and stack trace.

  3. Don’t Swallow Exceptions: Avoid empty catch blocks that swallow exceptions. If you catch an exception, handle it in some way, even if it means rethrowing it.

  4. Use the using Statement: When working with disposable objects like files, use the using statement to ensure proper cleanup and disposal.

  5. Avoid Exception-Heavy Logic: Minimize the use of exceptions for flow control. Instead, use conditionals to handle expected scenarios.

  6. Centralized Exception Handling: Consider centralizing your exception handling in a dedicated error-handling component or middleware.

  7. Check for Null: Always check for null values before accessing objects to prevent null reference exceptions.

  8. Keep Exception Messages Clear: Exception messages should be informative but not reveal sensitive information. Avoid exposing internal details.

7.10 Conclusion of Chapter 7

In Chapter 7, you’ve learned the importance of exception handling in C# and how to effectively handle and manage exceptions. You’ve explored the exception hierarchy, how to throw and catch exceptions, and best practices for robust error management.

Exception handling is a critical aspect of software development, ensuring that your applications remain stable and provide a better user experience by gracefully handling unexpected errors. By following best practices and using custom exceptions when needed, you can create more reliable and maintainable C# applications.

Scroll to Top