Tutorials / C# Programming

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.

C# Application Types
Web Apps
ASP.NET Core
Desktop
WPF, WinForms
Mobile
MAUI, Xamarin
Games
Unity Engine

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

Installation Steps
# 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
▶ OUTPUT
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.

Program Execution Flow
Compiler
csc.exe
IL Code
.exe/.dll
.NET Runtime
CLR
Output
Result
C# - Hello World
// 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.");
        }
    }
}
▶ OUTPUT
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.

How Variables Work in Memory
Memory
Allocated
Assignment
age = 25;
Value Stored
25

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
C# - Variables Example
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}");
    }
}
▶ OUTPUT
=== 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.

Value Types vs Reference Types
Value Types
int, double, bool, char
vs
Reference Types
string, arrays, objects
C# - All Data Types
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}");
    }
}
▶ OUTPUT
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.

C# - Type Conversion
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}");
    }
}
▶ OUTPUT
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?"

If-Else Decision Flow
TRUE
"Adult"
FALSE
"Minor"
C# - If-Else Statements
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
    }
}
▶ OUTPUT
=== 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.

C# - Switch Statement
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}");
    }
}
▶ OUTPUT
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.

Loop Types Comparison
for
Known count
while
Unknown count
foreach
Collections
C# - All Loop Types
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}");
    }
}
▶ OUTPUT
=== 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.

Class vs Object
Object 1
Instance
Object 2
Instance
Object 3
Instance

🔑 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

C# - Classes and Objects
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()}");
    }
}
▶ OUTPUT
=== 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.

Inheritance Hierarchy
Dog
Derived Class
Cat
Derived Class
C# - Inheritance
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
    }
}
▶ OUTPUT
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.

C# - 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();
    }
}
▶ OUTPUT
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.

LINQ Query Flow
LINQ Query
Filter/Transform
Result
IEnumerable
C# - LINQ Examples
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; }
}
▶ OUTPUT
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.

Sync vs Async Execution
Sync
Blocks & Waits
vs
Async
Non-blocking
C# - Async/Await
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);
    }
}
▶ OUTPUT
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.

C# - Generics
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;
    }
}
▶ OUTPUT
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.

Exception Handling Flow
catch
Handle error
finally
Cleanup
C# - Exception Handling
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}");
    }
}
▶ OUTPUT
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