;

Built-in Exception Classes in C#


Exception handling is a fundamental concept in C# programming, allowing applications to handle errors gracefully. C# provides several built-in exception classes within the .NET framework to handle various types of runtime errors. This tutorial explores these built-in exception classes, with examples to illustrate how they are used in real-world applications.

Introduction to Exception Handling

In C#, exceptions provide a structured approach to handling errors that may occur during runtime. By using exception handling techniques like try, catch, and finally blocks, you can manage unexpected scenarios without crashing the application.

Common Built-in Exception Classes

SystemException

The SystemException class serves as the base class for exceptions in the .NET framework. Most other exception classes inherit from it.

Example:

try
{
    int x = int.Parse("abc");
}
catch (SystemException ex)
{
    Console.WriteLine($"System Exception: {ex.Message}");
}

ArgumentException

The ArgumentException is thrown when a method receives an argument that is not valid.

Example:

public static void SetAge(int age)
{
    if (age < 0 || age > 120)
        throw new ArgumentException("Age must be between 0 and 120.");
}

try
{
    SetAge(-5);
}
catch (ArgumentException ex)
{
    Console.WriteLine($"Argument Exception: {ex.Message}");
}

NullReferenceException

A NullReferenceException occurs when an application tries to use an object reference that has not been initialized.

Example:

string name = null;
try
{
    Console.WriteLine(name.Length);
}
catch (NullReferenceException ex)
{
    Console.WriteLine($"Null Reference Exception: {ex.Message}");
}

IndexOutOfRangeException

This exception is thrown when code attempts to access an array element with an invalid index.

Example:

int[] numbers = { 1, 2, 3 };
try
{
    Console.WriteLine(numbers[3]);
}
catch (IndexOutOfRangeException ex)
{
    Console.WriteLine($"Index Out of Range Exception: {ex.Message}");
}

InvalidOperationException

An InvalidOperationException is thrown when a method call is invalid for the current state of the object.

Example:

List<int> numbers = new List<int> { 1, 2, 3 };
var enumerator = numbers.GetEnumerator();
enumerator.MoveNext();
enumerator.MoveNext();
enumerator.MoveNext();
try
{
    enumerator.MoveNext();  // Throws InvalidOperationException
}
catch (InvalidOperationException ex)
{
    Console.WriteLine($"Invalid Operation Exception: {ex.Message}");
}

FileNotFoundException

The FileNotFoundException is thrown when an attempt to access a file that does not exist on disk is made.

Example:

try
{
    using (var reader = new StreamReader("nonexistentfile.txt"))
    {
        Console.WriteLine(reader.ReadToEnd());
    }
}
catch (FileNotFoundException ex)
{
    Console.WriteLine($"File Not Found Exception: {ex.Message}");
}

IOException

An IOException occurs when an I/O operation fails, such as reading from or writing to a file.

Example:

try
{
    using (var file = File.Open("readonlyfile.txt", FileMode.Open, FileAccess.Write))
    {
        // Do something
    }
}
catch (IOException ex)
{
    Console.WriteLine($"IO Exception: {ex.Message}");
}

Real-World Example: User Data Import

Consider an application that imports user data from a file and processes it. Multiple exceptions may be encountered, such as the file not being found, invalid data format, or a missing data entry.

Example

using System;
using System.IO;

class UserDataImporter
{
    public void ImportData(string filePath)
    {
        try
        {
            if (!File.Exists(filePath))
                throw new FileNotFoundException("The data file is missing.");

            using (var reader = new StreamReader(filePath))
            {
                while (!reader.EndOfStream)
                {
                    var line = reader.ReadLine();
                    var parts = line.Split(',');

                    if (parts.Length < 2)
                        throw new ArgumentException("Data line is incomplete.");

                    string name = parts[0];
                    int age;
                    if (!int.TryParse(parts[1], out age))
                        throw new FormatException("Invalid format for age.");

                    Console.WriteLine($"Name: {name}, Age: {age}");
                }
            }
        }
        catch (FileNotFoundException ex)
        {
            Console.WriteLine($"File Error: {ex.Message}");
        }
        catch (ArgumentException ex)
        {
            Console.WriteLine($"Argument Error: {ex.Message}");
        }
        catch (FormatException ex)
        {
            Console.WriteLine($"Format Error: {ex.Message}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"General Error: {ex.Message}");
        }
    }
}

class Program
{
    static void Main()
    {
        var importer = new UserDataImporter();
        importer.ImportData("userdata.txt");
    }
}

Explanation

  1. File Check: FileNotFoundException handles cases where the specified file path is incorrect or missing.
  2. Data Format: ArgumentException catches cases where data is incomplete.
  3. Type Conversion: FormatException manages type conversion errors.
  4. Generic Catch: Any unanticipated errors are caught in the final Exception catch block.

This example showcases a multi-layered exception handling approach, addressing various potential errors that may occur during file-based data processing.

Key Takeaways

  • SystemException as a Base: Many exceptions inherit from SystemException, providing a foundational layer.
  • Context-Specific Exceptions: Built-in exceptions like NullReferenceException and InvalidOperationException address common issues in C#.
  • Error Segmentation: Catching specific exceptions allows precise error handling, enhancing application stability.
  • Real-World Applications: Built-in exceptions simplify error handling for file processing, data validation, and more.

Summary

Built-in exception classes in C# offer a robust way to handle specific errors without creating custom error types. By using classes like ArgumentException, FileNotFoundException, and IOException, developers can address common issues effectively, improving code readability and maintainability. In real-world scenarios, such as data imports, a well-designed exception handling strategy helps prevent crashes and allows for controlled error messaging. Embracing C#'s built-in exceptions equips developers to build more reliable, user-friendly applications.