C# Programming C#
Master C# from fundamentals to advanced concepts with practical examples
1 Introduction to C#
C# (pronounced "C-Sharp") is a modern, object-oriented programming language developed by Microsoft. It's part of the .NET ecosystem and is used to build a wide variety of applications including web apps, desktop software, mobile apps, games (Unity), and cloud services.
🔑 Key Concept
C# is a statically-typed language, meaning variable types are checked at compile time. This catches many errors before your program runs, making it safer and more reliable.
Why Learn C#?
- Versatility: Build any type of application with one language
- Industry Demand: Widely used in enterprise software and game development
- Modern Features: Regular updates with new language features
- Strong Tooling: Visual Studio provides excellent development experience
- Cross-Platform: .NET runs on Windows, macOS, and Linux
2 Environment Setup
Before writing C# code, you need to set up your development environment. Here are the tools you'll need:
🛠️ Required Tools
.NET SDK - The software development kit that includes the compiler and runtime
IDE - Visual Studio (recommended), VS Code, or JetBrains Rider
# Step 1: Download .NET SDK from Microsoft # Visit: https://dotnet.microsoft.com/download # Step 2: Verify installation in terminal/command prompt dotnet --version # Output: 8.0.100 (or your installed version) # Step 3: Create a new console project dotnet new console -n MyFirstApp cd MyFirstApp # Step 4: Run your application dotnet run
8.0.100 Hello, World!
💡 IDE Recommendations
Visual Studio - Full-featured IDE (Windows/Mac), best for large projects
VS Code - Lightweight, cross-platform, free with C# extension
JetBrains Rider - Cross-platform, powerful refactoring tools
3 Your First C# Program
Let's write the classic "Hello World" program. This simple program demonstrates the basic structure of a C# application and how to output text to the console.
// This is a single-line comment in C# // Comments are ignored by the compiler /* This is a multi-line comment. Use it for longer explanations. */ // 'using' imports namespaces (like importing libraries) using System; // 'namespace' organizes code into logical groups namespace MyFirstProgram { // 'class' defines a blueprint for objects class Program { // 'Main' is the entry point - where program starts // 'static' means it belongs to class, not instance // 'void' means it doesn't return any value static void Main(string[] args) { // Console.WriteLine prints text to the console // The text inside quotes is a 'string' Console.WriteLine("Hello, World!"); // Let's print more to understand output Console.WriteLine("Welcome to C# Programming!"); Console.WriteLine("This is your first program."); } } }
Hello, World! Welcome to C# Programming! This is your first program.
📝 Code Breakdown
using System; - Imports the System namespace which contains Console class
namespace - Organizes your code; prevents naming conflicts
class - Container for your code; everything in C# lives in a class
static void Main() - The starting point; program begins execution here
Console.WriteLine() - Method to print text followed by a new line
3 Variables and Data Types
Variables are containers that store data values. In C#, you must declare a variable's type before using it. This tells the compiler how much memory to allocate and what operations are valid.
Basic Data Types
| Type | Description | Example | Size |
|---|---|---|---|
int |
Whole numbers | int age = 25; |
4 bytes |
double |
Decimal numbers | double price = 19.99; |
8 bytes |
string |
Text | string name = "Alice"; |
Varies |
bool |
True/False | bool isActive = true; |
1 byte |
char |
Single character | char grade = 'A'; |
2 bytes |
using System; class VariablesDemo { static void Main() { // INTEGER - whole numbers without decimals int age = 25; int year = 2025; int score = -10; // Can be negative // DOUBLE - numbers with decimal points double price = 19.99; double temperature = -5.5; double pi = 3.14159; // STRING - text enclosed in double quotes string name = "Alice"; string greeting = "Hello, World!"; string empty = ""; // Empty string is valid // BOOLEAN - only true or false bool isStudent = true; bool hasPassed = false; // CHAR - single character in single quotes char grade = 'A'; char initial = 'J'; // Print all variables Console.WriteLine("=== Variable Values ==="); Console.WriteLine($"Name: {name}"); Console.WriteLine($"Age: {age}"); Console.WriteLine($"Price: ${price}"); Console.WriteLine($"Is Student: {isStudent}"); Console.WriteLine($"Grade: {grade}"); // VAR - compiler infers the type automatically var autoInt = 100; // Inferred as int var autoString = "Hi"; // Inferred as string Console.WriteLine($"\nAuto-typed: {autoInt}, {autoString}"); } }
=== Variable Values === Name: Alice Age: 25 Price: $19.99 Is Student: True Grade: A Auto-typed: 100, Hi
💡 Pro Tip: String Interpolation
The $"..." syntax is called string interpolation. It lets you embed variables
directly inside strings using {variableName}. Much cleaner than concatenation!
5 Data Types in Depth
C# is a strongly-typed language, meaning every variable must have a specific data type. Understanding data types helps you write efficient code and avoid errors.
using System; class DataTypesDemo { static void Main() { // INTEGER TYPES (whole numbers) byte smallNum = 255; // 0 to 255 (1 byte) short mediumNum = 32767; // -32,768 to 32,767 (2 bytes) int normalNum = 2147483647; // Most common (4 bytes) long bigNum = 9223372036854775807L; // Very large (8 bytes) // FLOATING POINT (decimal numbers) float price = 19.99f; // 7 digits precision (4 bytes) double pi = 3.14159265358979; // 15-16 digits precision (8 bytes) decimal money = 1234.56m; // 28-29 digits, best for money (16 bytes) // TEXT TYPES char letter = 'A'; // Single character string text = "Hello World"; // Text of any length // BOOLEAN bool isValid = true; // true or false only // DEFAULT VALUES (when not initialized) int defaultInt = default; // 0 bool defaultBool = default; // false string defaultStr = default; // null Console.WriteLine($"byte max: {byte.MaxValue}"); Console.WriteLine($"int max: {int.MaxValue}"); Console.WriteLine($"decimal for money: ${money}"); } }
byte max: 255 int max: 2147483647 decimal for money: $1234.56
⚠️ When to Use Which Type
int - Default choice for whole numbers
double - Scientific calculations
decimal - Financial/monetary calculations (most precise)
long - Only when int is too small
6 Type Conversion
Converting between data types is common in programming. C# supports implicit (automatic) and explicit (manual) conversions, plus parsing strings to numbers.
using System; class ConversionDemo { static void Main() { // IMPLICIT CONVERSION (automatic, safe) // Smaller type → Larger type (no data loss) int myInt = 100; long myLong = myInt; // int → long (automatic) double myDouble = myInt; // int → double (automatic) Console.WriteLine($"int: {myInt}, long: {myLong}, double: {myDouble}"); // EXPLICIT CONVERSION (casting, may lose data) // Larger type → Smaller type (requires cast) double price = 19.99; int rounded = (int)price; // Truncates decimal part! Console.WriteLine($"Original: {price}, Casted: {rounded}"); // CONVERT CLASS (safer conversions) double value = 9.8; int converted = Convert.ToInt32(value); // Rounds! Console.WriteLine($"Convert.ToInt32(9.8): {converted}"); // STRING TO NUMBER (Parsing) string strNum = "42"; int parsed = int.Parse(strNum); Console.WriteLine($"Parsed string '42' to int: {parsed}"); // TryParse (safe, won't crash on invalid input) string userInput = "abc"; if (int.TryParse(userInput, out int result)) { Console.WriteLine($"Parsed: {result}"); } else { Console.WriteLine($"'{userInput}' is not a valid number"); } // NUMBER TO STRING int num = 123; string strFromInt = num.ToString(); Console.WriteLine($"int to string: {strFromInt}"); } }
int: 100, long: 100, double: 100 Original: 19.99, Casted: 19 Convert.ToInt32(9.8): 10 Parsed string '42' to int: 42 'abc' is not a valid number int to string: 123
💡 Best Practices
• Use TryParse instead of Parse for user input
• Use Convert class when rounding is needed
• Be careful with casting - it truncates, doesn't round!
7 Control Flow: If-Else
Control flow statements let your program make decisions. The if-else statement
executes different code blocks based on conditions. Think of it as the program asking "Is this true?"
using System; class IfElseDemo { static void Main() { int age = 20; int score = 85; // Simple if statement Console.WriteLine("=== Simple If ==="); if (age >= 18) { Console.WriteLine("You are an adult."); } // If-else statement Console.WriteLine("\n=== If-Else ==="); if (score >= 60) { Console.WriteLine("You passed!"); } else { Console.WriteLine("You failed."); } // If-else if-else chain (multiple conditions) Console.WriteLine("\n=== Grade Calculation ==="); if (score >= 90) { Console.WriteLine("Grade: A - Excellent!"); } else if (score >= 80) { Console.WriteLine("Grade: B - Good job!"); } else if (score >= 70) { Console.WriteLine("Grade: C - Average"); } else if (score >= 60) { Console.WriteLine("Grade: D - Below average"); } else { Console.WriteLine("Grade: F - Failed"); } // Comparison operators demonstration Console.WriteLine($"\n=== Comparisons (score={score}) ==="); Console.WriteLine($"score == 85: {score == 85}"); // Equal to Console.WriteLine($"score != 100: {score != 100}"); // Not equal Console.WriteLine($"score > 80: {score > 80}"); // Greater than Console.WriteLine($"score < 90: {score < 90}"); // Less than Console.WriteLine($"score >= 85: {score >= 85}"); // Greater or equal Console.WriteLine($"score <= 85: {score <= 85}"); // Less or equal } }
=== Simple If === You are an adult. === If-Else === You passed! === Grade Calculation === Grade: B - Good job! === Comparisons (score=85) === score == 85: True score != 100: True score > 80: True score < 90: True score >= 85: True score <= 85: True
8 Switch Statement
The switch statement is an alternative to multiple if-else statements when comparing a single variable against many possible values. It's cleaner and more readable.
using System; class SwitchDemo { static void Main() { // Basic switch statement int dayNumber = 3; switch (dayNumber) { case 1: Console.WriteLine("Monday"); break; case 2: Console.WriteLine("Tuesday"); break; case 3: Console.WriteLine("Wednesday"); break; case 4: case 5: Console.WriteLine("Thursday or Friday"); break; default: Console.WriteLine("Weekend!"); break; } // Switch with strings string grade = "B"; switch (grade) { case "A": Console.WriteLine("Excellent!"); break; case "B": Console.WriteLine("Good job!"); break; case "C": Console.WriteLine("You passed"); break; default: Console.WriteLine("Keep trying"); break; } // Modern Switch Expression (C# 8.0+) int month = 4; string season = month switch { 12 or 1 or 2 => "Winter", >= 3 and <= 5 => "Spring", >= 6 and <= 8 => "Summer", _ => "Autumn" }; Console.WriteLine($"Month {month} is in {season}"); } }
Wednesday Good job! Month 4 is in Spring
💡 Switch vs If-Else
Use switch when comparing one variable against many exact values.
Use if-else when checking ranges or complex conditions.
9 Loops
Loops execute a block of code repeatedly. C# provides three main types of loops:
for, while, and foreach. Each serves different use cases.
using System; class LoopsDemo { static void Main() { // ======================================== // FOR LOOP - when you know how many times // ======================================== Console.WriteLine("=== FOR Loop ==="); // for (initialization; condition; increment) // i starts at 1, continues while i <= 5, adds 1 each time for (int i = 1; i <= 5; i++) { Console.WriteLine($"Count: {i}"); } // ======================================== // WHILE LOOP - when count is unknown // ======================================== Console.WriteLine("\n=== WHILE Loop ==="); int countdown = 3; while (countdown > 0) // Loop while condition is true { Console.WriteLine($"{countdown}..."); countdown--; // Decrease by 1 (same as countdown = countdown - 1) } Console.WriteLine("Liftoff! 🚀"); // ======================================== // FOREACH LOOP - iterate over collections // ======================================== Console.WriteLine("\n=== FOREACH Loop ==="); string[] fruits = { "Apple", "Banana", "Cherry", "Date" }; // foreach automatically iterates through each item foreach (string fruit in fruits) { Console.WriteLine($"I like {fruit}"); } // ======================================== // Practical Example: Sum of numbers // ======================================== Console.WriteLine("\n=== Sum Calculation ==="); int[] numbers = { 10, 20, 30, 40, 50 }; int sum = 0; foreach (int num in numbers) { sum += num; // Add each number to sum } Console.WriteLine($"Numbers: 10, 20, 30, 40, 50"); Console.WriteLine($"Sum: {sum}"); Console.WriteLine($"Average: {sum / numbers.Length}"); } }
=== FOR Loop === Count: 1 Count: 2 Count: 3 Count: 4 Count: 5 === WHILE Loop === 3... 2... 1... Liftoff! 🚀 === FOREACH Loop === I like Apple I like Banana I like Cherry I like Date === Sum Calculation === Numbers: 10, 20, 30, 40, 50 Sum: 150 Average: 30
6 Classes and Objects
Object-Oriented Programming (OOP) is the heart of C#. A class is a blueprint that defines properties (data) and methods (actions). An object is an instance of a class - a concrete thing created from the blueprint.
🔑 OOP Key Concepts
Encapsulation: Bundling data and methods together
Inheritance: Creating new classes based on existing ones
Polymorphism: Objects behaving differently based on their type
Abstraction: Hiding complexity, showing only what's necessary
using System; // Define a class - blueprint for creating objects class Person { // PROPERTIES - data the class holds // 'public' means accessible from outside the class public string Name { get; set; } public int Age { get; set; } public string Email { get; set; } // CONSTRUCTOR - special method called when creating object public Person(string name, int age, string email) { // 'this' refers to the current instance this.Name = name; this.Age = age; this.Email = email; } // METHOD - action the class can perform public void Introduce() { Console.WriteLine($"Hi! I'm {Name}, {Age} years old."); Console.WriteLine($"Contact me at: {Email}"); } // Method with return value public bool IsAdult() { return Age >= 18; } // Method with parameters public void CelebrateBirthday() { Age++; // Increase age by 1 Console.WriteLine($"🎂 Happy Birthday! {Name} is now {Age}!"); } } class Program { static void Main() { Console.WriteLine("=== Creating Objects ==="); // Create objects (instances) of the Person class Person person1 = new Person("Alice", 25, "alice@email.com"); Person person2 = new Person("Bob", 17, "bob@email.com"); // Call methods on objects Console.WriteLine("\n--- Person 1 ---"); person1.Introduce(); Console.WriteLine($"Is Adult: {person1.IsAdult()}"); Console.WriteLine("\n--- Person 2 ---"); person2.Introduce(); Console.WriteLine($"Is Adult: {person2.IsAdult()}"); // Modify object state Console.WriteLine("\n--- Birthday! ---"); person2.CelebrateBirthday(); Console.WriteLine($"Is Adult now: {person2.IsAdult()}"); } }
=== Creating Objects === --- Person 1 --- Hi! I'm Alice, 25 years old. Contact me at: alice@email.com Is Adult: True --- Person 2 --- Hi! I'm Bob, 17 years old. Contact me at: bob@email.com Is Adult: False --- Birthday! --- 🎂 Happy Birthday! Bob is now 18! Is Adult now: True
11 Inheritance
Inheritance allows a class to inherit properties and methods from another class. The derived class (child) gets all features of the base class (parent) and can add or override them.
using System; // BASE CLASS (Parent) class Animal { public string Name { get; set; } public int Age { get; set; } // Virtual method - can be overridden public virtual void Speak() { Console.WriteLine("Animal makes a sound"); } public void Eat() { Console.WriteLine($"{Name} is eating"); } } // DERIVED CLASS (Child) - inherits from Animal class Dog : Animal { public string Breed { get; set; } // Override the base method public override void Speak() { Console.WriteLine($"{Name} says: Woof! Woof!"); } // New method specific to Dog public void Fetch() { Console.WriteLine($"{Name} is fetching the ball!"); } } class Cat : Animal { public override void Speak() { Console.WriteLine($"{Name} says: Meow!"); } } class Program { static void Main() { Dog dog = new Dog { Name = "Buddy", Age = 3, Breed = "Golden Retriever" }; Cat cat = new Cat { Name = "Whiskers", Age = 2 }; dog.Speak(); // Overridden method dog.Eat(); // Inherited from Animal dog.Fetch(); // Dog-specific method cat.Speak(); // Overridden method cat.Eat(); // Inherited from Animal } }
Buddy says: Woof! Woof! Buddy is eating Buddy is fetching the ball! Whiskers says: Meow! Whiskers is eating
🔑 Key Inheritance Terms
base - Access parent class members
virtual - Method can be overridden in derived class
override - Replace the parent's implementation
sealed - Prevent further inheritance
12 Interfaces
An interface defines a contract - a set of methods and properties that a class must implement. Unlike inheritance (one parent), a class can implement multiple interfaces.
using System; // Interface definition - starts with 'I' by convention interface IVehicle { // Interface members are public by default void Start(); void Stop(); int Speed { get; set; } } interface IElectric { int BatteryLevel { get; } void Charge(); } // Class implementing multiple interfaces class Tesla : IVehicle, IElectric { public int Speed { get; set; } public int BatteryLevel { get; private set; } = 100; public void Start() { Console.WriteLine("Tesla starting silently..."); } public void Stop() { Speed = 0; Console.WriteLine("Tesla stopped"); } public void Charge() { BatteryLevel = 100; Console.WriteLine("Charging... Battery at 100%"); } } class GasCar : IVehicle { public int Speed { get; set; } public void Start() { Console.WriteLine("Engine roaring..."); } public void Stop() { Speed = 0; Console.WriteLine("Engine off"); } } class Program { static void Main() { // Polymorphism: different types, same interface IVehicle[] vehicles = { new Tesla(), new GasCar() }; foreach (IVehicle v in vehicles) { v.Start(); v.Stop(); Console.WriteLine(); } // Using interface reference IElectric myTesla = new Tesla(); myTesla.Charge(); } }
Tesla starting silently... Tesla stopped Engine roaring... Engine off Charging... Battery at 100%
💡 Interface vs Abstract Class
Interface: No implementation, multiple inheritance allowed
Abstract Class: Can have implementation, single inheritance only
13 LINQ (Language Integrated Query)
LINQ allows you to query collections (arrays, lists, databases) using a SQL-like syntax directly in C#. It's one of C#'s most powerful features for data manipulation.
using System; using System.Linq; using System.Collections.Generic; class LinqDemo { static void Main() { // Sample data int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // WHERE - Filter elements var evens = numbers.Where(n => n % 2 == 0); Console.WriteLine("Even numbers: " + string.Join(", ", evens)); // SELECT - Transform elements var squared = numbers.Select(n => n * n); Console.WriteLine("Squared: " + string.Join(", ", squared)); // Combined: Filter then Transform var result = numbers .Where(n => n > 5) .Select(n => n * 2); Console.WriteLine(">5 then doubled: " + string.Join(", ", result)); // ORDERBY - Sort elements var descending = numbers.OrderByDescending(n => n); Console.WriteLine("Descending: " + string.Join(", ", descending)); // Aggregation methods Console.WriteLine($"Sum: {numbers.Sum()}"); Console.WriteLine($"Average: {numbers.Average()}"); Console.WriteLine($"Max: {numbers.Max()}"); Console.WriteLine($"Count > 5: {numbers.Count(n => n > 5)}"); // FIRST, LAST, SINGLE Console.WriteLine($"First even: {numbers.First(n => n % 2 == 0)}"); Console.WriteLine($"Last: {numbers.Last()}"); // ANY, ALL - Boolean checks Console.WriteLine($"Any > 9? {numbers.Any(n => n > 9)}"); Console.WriteLine($"All positive? {numbers.All(n => n > 0)}"); // Working with objects var people = new List<Person> { new Person { Name = "Alice", Age = 25, City = "NYC" }, new Person { Name = "Bob", Age = 30, City = "LA" }, new Person { Name = "Carol", Age = 28, City = "NYC" } }; // Query syntax (alternative to method syntax) var nycPeople = from p in people where p.City == "NYC" orderby p.Age select p.Name; Console.WriteLine("NYC residents: " + string.Join(", ", nycPeople)); } } class Person { public string Name { get; set; } public int Age { get; set; } public string City { get; set; } }
Even numbers: 2, 4, 6, 8, 10 Squared: 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 >5 then doubled: 12, 14, 16, 18, 20 Descending: 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 Sum: 55 Average: 5.5 Max: 10 Count > 5: 5 First even: 2 Last: 10 Any > 9? True All positive? True NYC residents: Alice, Carol
💡 LINQ Method Cheat Sheet
Where() - Filter | Select() - Transform | OrderBy() - Sort
First() - Get first | Any() - Check exists | All() - Check all
Sum(), Average(), Count(), Max(), Min() - Aggregates
8 Async/Await
Asynchronous programming allows your application to perform time-consuming operations (like API calls, file I/O) without blocking the main thread. This keeps your app responsive.
using System; using System.Threading.Tasks; using System.Net.Http; class AsyncDemo { // Main can be async in C# 7.1+ static async Task Main() { Console.WriteLine("Starting..."); // Call async method and AWAIT result string result = await GetMessageAsync(); Console.WriteLine(result); // Multiple async operations in parallel Task<string> task1 = GetMessageAsync("Task 1", 1000); Task<string> task2 = GetMessageAsync("Task 2", 500); Task<string> task3 = GetMessageAsync("Task 3", 1500); // Wait for ALL tasks to complete string[] results = await Task.WhenAll(task1, task2, task3); Console.WriteLine("\nAll tasks completed:"); foreach (var r in results) Console.WriteLine(r); // Practical example: HTTP request try { string data = await FetchDataAsync("https://api.example.com/data"); Console.WriteLine(data); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); } } // Async method returns Task or Task<T> static async Task<string> GetMessageAsync() { // Simulate async work (e.g., API call) await Task.Delay(1000); // Non-blocking wait return "Hello from async method!"; } static async Task<string> GetMessageAsync(string name, int delayMs) { await Task.Delay(delayMs); return $"{name} completed after {delayMs}ms"; } // Real-world: HTTP client static async Task<string> FetchDataAsync(string url) { using var client = new HttpClient(); return await client.GetStringAsync(url); } }
Starting... Hello from async method! All tasks completed: Task 1 completed after 1000ms Task 2 completed after 500ms Task 3 completed after 1500ms
🔑 Async/Await Rules
async - Marks a method as asynchronous
await - Pauses execution until Task completes (non-blocking)
Task - Represents an async operation (void equivalent)
Task<T> - Async operation that returns a value
9 Generics
Generics allow you to write type-safe, reusable code. Instead of writing separate methods for int, string, etc., write one generic method that works with any type.
using System; using System.Collections.Generic; class GenericsDemo { static void Main() { // Generic method - works with any type! PrintValue<int>(42); PrintValue<string>("Hello"); PrintValue<double>(3.14); // Swap any two values int a = 10, b = 20; Console.WriteLine($"Before swap: a={a}, b={b}"); Swap(ref a, ref b); Console.WriteLine($"After swap: a={a}, b={b}"); // Generic class var intBox = new Box<int>(100); var stringBox = new Box<string>("Secret"); Console.WriteLine($"Int box: {intBox.Value}"); Console.WriteLine($"String box: {stringBox.Value}"); // Built-in generic collections List<string> names = new List<string> { "Alice", "Bob" }; Dictionary<string, int> ages = new Dictionary<string, int> { { "Alice", 25 }, { "Bob", 30 } }; Console.WriteLine($"Alice's age: {ages["Alice"]}"); } // Generic method with type parameter T static void PrintValue<T>(T value) { Console.WriteLine($"Type: {typeof(T).Name}, Value: {value}"); } // Generic swap method static void Swap<T>(ref T x, ref T y) { T temp = x; x = y; y = temp; } } // Generic class class Box<T> { public T Value { get; private set; } public Box(T value) { Value = value; } }
Type: Int32, Value: 42 Type: String, Value: Hello Type: Double, Value: 3.14 Before swap: a=10, b=20 After swap: a=20, b=10 Int box: 100 String box: Secret Alice's age: 25
10 Exception Handling
Exceptions are runtime errors that can crash your program. Exception handling with try-catch-finally lets you gracefully handle errors and keep your app running.
using System; class ExceptionDemo { static void Main() { // Basic try-catch try { int result = 10 / 0; // This throws DivideByZeroException } catch (DivideByZeroException ex) { Console.WriteLine($"Error: {ex.Message}"); } // Multiple catch blocks try { string[] arr = { "a", "b" }; Console.WriteLine(arr[10]); // IndexOutOfRangeException } catch (IndexOutOfRangeException ex) { Console.WriteLine($"Index error: {ex.Message}"); } catch (Exception ex) // Catches any other exception { Console.WriteLine($"General error: {ex.Message}"); } // try-catch-finally try { Console.WriteLine("Opening file..."); // Simulate file operation throw new Exception("File not found"); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); } finally { // Always executes - use for cleanup Console.WriteLine("Closing file (cleanup)"); } // Throwing custom exceptions try { ValidateAge(-5); } catch (ArgumentException ex) { Console.WriteLine($"Validation error: {ex.Message}"); } Console.WriteLine("\nProgram continues after exceptions!"); } static void ValidateAge(int age) { if (age < 0) { throw new ArgumentException("Age cannot be negative"); } Console.WriteLine($"Valid age: {age}"); } }
Error: Attempted to divide by zero. Index error: Index was outside the bounds of the array. Opening file... Error: File not found Closing file (cleanup) Validation error: Age cannot be negative Program continues after exceptions!
⚠️ Exception Best Practices
• Catch specific exceptions, not just Exception
• Use finally for cleanup (closing files, connections)
• Don't use exceptions for normal control flow
• Include meaningful error messages when throwing