Syntax
try {\n // risky code\n} catch (ExceptionType e) {\n // handle it\n} finally {\n // always runs\n}Examples
Basic try / catch
Catching an exception instead of letting the program crash.
try
{
int result = 10 / int.Parse("0");
}
catch (DivideByZeroException e)
{
Console.WriteLine($"Error: {e.Message}");
}
Console.WriteLine("Program continues running");Catching Multiple Exception Types
Handling different exceptions differently with multiple catch blocks.
void Process(string input)
{
try
{
int number = int.Parse(input);
int result = 100 / number;
Console.WriteLine(result);
}
catch (FormatException)
{
Console.WriteLine($"Not a valid number: {input}");
}
catch (DivideByZeroException)
{
Console.WriteLine("Cannot divide by zero");
}
}
Process("abc"); // Not a valid number: abc
Process("0"); // Cannot divide by zero
Process("5"); // 20finally and using
Code in finally always executes; the using statement automatically disposes resources, even on exception.
void ReadFile()
{
Console.WriteLine("Opening file...");
try
{
throw new InvalidOperationException("File not found");
}
catch (InvalidOperationException e)
{
Console.WriteLine($"Error: {e.Message}");
}
finally
{
Console.WriteLine("Closing file..."); // always runs
}
}
ReadFile();Custom Exceptions
Defining and throwing your own exception type for domain-specific error handling.
public class InsufficientFundsException : Exception
{
public InsufficientFundsException(string message) : base(message) { }
}
public class BankAccount
{
private double _balance;
public BankAccount(double balance) => _balance = balance;
public void Withdraw(double amount)
{
if (amount > _balance)
throw new InsufficientFundsException("Not enough funds for this withdrawal");
_balance -= amount;
}
}
BankAccount account = new BankAccount(100);
try
{
account.Withdraw(200);
}
catch (InsufficientFundsException e)
{
Console.WriteLine($"Transaction failed: {e.Message}");
}Best practices
- Catch specific exception types rather than a broad catch (Exception e), so unrelated bugs are not accidentally silenced
- Use finally (or better, a using statement/declaration) for cleanup code that absolutely must run, like closing files or database connections
- Create custom exception classes, deriving from Exception, for domain-specific errors that callers should be able to catch distinctly
- Don't use exceptions for routine control flow when a simple if check (or TryParse-style pattern) would do - they carry real performance overhead
At a glance
- Purpose
- Applications on the .NET platform
- File extension
- .cs
- Runs in
- .NET runtime
- Usually used with
- .NET SDK and libraries
Specifications & further reading
Related C# documentation
A class is a blueprint for creating objects, bundling related data (fields/properties) and behavior (methods) together. C# is a fully object-oriented language - every application has at least one class, typically with a Main method as its entry point. An object is a specific instance of a class, created with the new keyword, with its own independent copy of the class's instance data.Constructors
A constructor is a special method that runs automatically when an object is created with new, used to initialize the object's state. A constructor shares its name with the class and has no return type. C# supports constructor overloading (multiple constructors with different parameter lists) and constructor chaining with this(...), where one constructor calls another in the same class to avoid duplicating initialization logic.Properties (get/set)
Properties are C#'s idiomatic way to expose class data through accessor-like syntax while still allowing controlled access via get and set. Unlike a plain public field, a property can validate a value before it's set, compute a value on the fly, or restrict access to read-only. Auto-implemented properties (using { get; set; } with no body) provide a concise shorthand when no custom logic is needed.Access Modifiers
Access modifiers control the visibility of classes, fields, methods, and properties from other parts of a program. C# provides public (accessible from anywhere), private (accessible only within the declaring class - the default for class members), protected (accessible within the class and its subclasses), internal (accessible only within the same assembly/project), and combinations like protected internal and private protected.