Exception Handling in C#: Try, Catch, Finally, Throw, and Best Practices

Errors are a normal part of software development. Applications interact with files, databases, web services, user input, and external systems, all of which can fail unexpectedly.

Exception handling allows developers to detect, manage, and respond to runtime errors without causing an application to crash unexpectedly.

In this guide, you'll learn the fundamentals of exception handling in C#, including try-catch blocks, finally statements, custom exceptions, and best practices for writing reliable applications.


What Is an Exception?

An exception is an error that occurs while a program is running. When an exception is not handled properly, the application may terminate unexpectedly.

int number = 10;
            int result = number / 0;

This code throws a DivideByZeroException because division by zero is not allowed.

Why Exception Handling Matters

Proper exception handling helps applications:

  • Prevent unexpected crashes.
  • Provide helpful error messages.
  • Protect important data.
  • Improve user experience.
  • Support troubleshooting and logging.

Well-handled exceptions contribute to more reliable and maintainable software.

Using try and catch

The most common way to handle exceptions is by using a try-catch block.

try
                {
                int number = 10;
                int result = number / 0;

                Console.WriteLine(result);
                }
                catch
                {
                Console.WriteLine("An error occurred.");
                }

Output

An error occurred.

If an exception occurs inside the try block, execution moves to the catch block.

Handling Specific Exceptions

It is usually better to catch specific exception types.

try
                    {
                    int result = 10 / 0;
                    }
                    catch (DivideByZeroException)
                    {
                    Console.WriteLine("Division by zero is not allowed.");
                    }

This approach makes error handling more precise and easier to maintain.

Accessing Exception Details

The exception object contains useful information about the error.

try
                        {
                        int result = 10 / 0;
                        }
                        catch (Exception ex)
                        {
                        Console.WriteLine(ex.Message);
                        }

The Message property provides a human-readable description of the problem.

Using Multiple Catch Blocks

Different exceptions can be handled in different ways.

try
                            {
                            string text = null;

                            Console.WriteLine(text.Length);
                            }
                            catch (NullReferenceException)
                            {
                            Console.WriteLine("Object reference is null.");
                            }
                            catch (Exception)
                            {
                            Console.WriteLine("An unexpected error occurred.");
                            }

The most specific exception types should appear before more general ones.

Using the finally Block

The finally block always executes, whether an exception occurs or not.

try
                                {
                                Console.WriteLine("Processing...");
                                }
                                catch
                                {
                                Console.WriteLine("Error.");
                                }
                                finally
                                {
                                Console.WriteLine("Cleanup completed.");
                                }

Output

Processing...
                                    Cleanup completed.

Finally blocks are commonly used for resource cleanup.

Throwing Exceptions

Developers can create exceptions using the throw keyword.

int age = -1;

                                        if (age < 0)
                                              {
                                              throw new ArgumentException(
                                              "Age cannot be negative.");
                                              }

Throwing exceptions allows invalid situations to be detected early.

Creating Custom Exceptions

Applications can define their own exception types.

public class InvalidCustomerException
                                            : Exception
                                            {
                                            public InvalidCustomerException(string message)
                                            : base(message)
                                            {
                                            }
                                            }

Custom exceptions can make error handling more meaningful within business applications.

Common Exceptions in C#

Exception Description
DivideByZeroException Division by zero attempted.
NullReferenceException Object reference is null.
IndexOutOfRangeException Invalid array index.
FormatException Invalid format conversion.
ArgumentException Invalid method argument.
FileNotFoundException File could not be located.

Exception Handling with Async Methods

Asynchronous methods use the same exception handling principles.

try
                                                {
                                                await Task.Delay(1000);

                                                throw new Exception("Sample error.");
                                                }
                                                catch (Exception ex)
                                                {
                                                Console.WriteLine(ex.Message);
                                                }

Exceptions thrown from asynchronous operations should still be handled appropriately.

Common Mistakes to Avoid

  • Catching every exception without handling it properly.
  • Ignoring exception details.
  • Using exceptions for normal program flow.
  • Leaving catch blocks empty.
  • Exposing sensitive system information to users.

Best Practices

  • Catch specific exceptions whenever possible.
  • Log important errors.
  • Use meaningful exception messages.
  • Clean up resources with finally blocks.
  • Validate input before processing.
  • Avoid swallowing exceptions silently.

Real-World Examples

  • Validating form submissions.
  • Reading configuration files.
  • Processing API responses.
  • Database operations.
  • File uploads and downloads.
  • Payment processing systems.

Frequently Asked Questions

What is an exception in C#?

An exception is a runtime error that interrupts normal program execution.

What is the purpose of try-catch?

Try-catch blocks allow applications to handle errors gracefully.

What does finally do?

The finally block executes regardless of whether an exception occurs.

Should I catch all exceptions?

It's generally better to catch specific exception types whenever possible.

Related Tutorials

Conclusion

Exception handling is a critical skill for every C# developer. Understanding how to use try, catch, finally, and throw statements helps create applications that are more stable, reliable, and easier to maintain.

By following best practices and handling errors thoughtfully, you can build software that responds gracefully to unexpected situations and provides a better experience for users.