🚀 C# ile Programlamaya Giriş: Kodlamaya İlk Adımını At, Kendi Projelerini Geliştirmeye Başla!
00HOME 01POSTS 02COURSES 03ELECTRİCAL_ENERGY 04AUTOMOTİVE_ENGİNEERİNG 05TOOLS 06LAB 07GLOSSARY 08TAGS ♡MY LIST ⌕SEARCH
TRENG

Error Handling: try, catch, finally

Keep your program from crashing when something goes wrong: the exception concept, try/catch/finally, throw, your own exception class and cleanup with using.

What is an exception?

While a program runs, an unexpected situation occurs: dividing by zero, opening a file that doesn't exist, accessing an index that is not in the list... In these cases .NET throws an exception object. If it is not caught, the program prints a message and closes. Our goal is to be prepared for these situations and to respond to the user properly.

try - catch

try
{
    Console.Write("Enter a number: ");
    int number = int.Parse(Console.ReadLine()!);
    Console.WriteLine($"100 / {number} = {100 / number}");
}
catch (FormatException)
{
    Console.WriteLine("That is not a number.");
}
catch (DivideByZeroException)
{
    Console.WriteLine("You cannot divide by zero.");
}

You put the risky code in the try block. If an exception occurs inside it, the flow jumps immediately to the matching catch block. By writing several catch blocks you can handle different errors separately; order them from specific to general.

Enter a number: abc
That is not a number.

Accessing the exception object

try
{
    int[] array = { 1, 2, 3 };
    Console.WriteLine(array[5]);
}
catch (Exception ex)
{
    Console.WriteLine($"Error type: {ex.GetType().Name}");
    Console.WriteLine($"Message: {ex.Message}");
}
Error type: IndexOutOfRangeException
Message: Index was outside the bounds of the array.

Error messages can come in English or in another language depending on .NET's language setting. Exception is the ancestor of all errors; a general catch placed at the very end works as a catch-all.

finally: the block that runs in every case

Cleanup jobs such as closing a file or releasing a connection must be done whether there was an error or not. The finally block is for this:

StreamReader? reader = null;
try
{
    reader = new StreamReader("measurements.txt");
    Console.WriteLine(reader.ReadLine());
}
catch (FileNotFoundException)
{
    Console.WriteLine("measurements.txt was not found.");
}
finally
{
    reader?.Dispose();    // close it if it is open
    Console.WriteLine("Cleanup done.");
}

The ?. operator means "call it if the object is not null".

using: a shortcut for cleanup

For objects that must be closed, such as files, the using declaration closes the object automatically when the block ends; it saves you from writing finally:

try
{
    using var reader = new StreamReader("measurements.txt");
    string? line;
    while ((line = reader.ReadLine()) != null)
    {
        Console.WriteLine(line);
    }
}
catch (FileNotFoundException)
{
    Console.WriteLine("No such file.");
}

throw: raise the error yourself

If a method receives invalid input, instead of quietly returning a wrong result it should throw an error:

static double Current(double voltage, double resistance)
{
    if (resistance <= 0)
        throw new ArgumentOutOfRangeException(nameof(resistance), "Resistance must be greater than zero.");
    return voltage / resistance;
}

try
{
    Console.WriteLine(Current(5, 0));
}
catch (ArgumentOutOfRangeException ex)
{
    Console.WriteLine("Invalid: " + ex.ParamName);
}
Invalid: resistance

Writing your own exception class

For an error specific to your field, you can derive from Exception:

try
{
    double current = 12.5;
    if (current > 10) throw new OvercurrentException(current);
}
catch (OvercurrentException ex)
{
    Console.WriteLine(ex.Message);
}

class OvercurrentException : Exception
{
    public double Current { get; }

    public OvercurrentException(double current)
        : base($"Current limit exceeded: {current} A")
    {
        Current = current;
    }
}
Current limit exceeded: 12.5 A

Anti-pattern: Don't write catch (Exception) { } and swallow the error. The problem gets hidden and becomes very hard to find later. If you catch it, either fix it, log it, or rethrow it (throw;).

Tip: For expected situations (the user typed an invalid number), prefer controlled methods such as TryParse instead of an exception. Exceptions are for things that "should not happen"; they are also relatively slow.

Try it yourself

Write a program that asks the user for a file name and prints the number of lines in the file. Give three separate messages: if the file doesn't exist, if there is no permission to read it (UnauthorizedAccessException), and if any other error occurs. Open the file with using.

// Mini quiz

Click an option; you will see right away, with the reason, whether it is correct or not.

1. When does the finally block run?
2. In what order should you write multiple catch blocks?
3. What is the benefit of using var reader = new StreamReader(...) with using?

Mark it when you finish: your progress is saved and you earn +20 XP.

Tip: ← → keys let you move between lessons.