C# Mastery Guide
Complete guide from beginner to advanced
The Complete C# Mastery Guide
A comprehensive journey through C# fundamentals to advanced .NET development concepts.
Understanding C#: The Modern .NET Language
C# (pronounced "C Sharp") is a modern, object-oriented, and type-safe programming language developed by Microsoft. Created by Anders Hejlsberg and his team in 2000, C# has evolved into one of the most popular languages for building enterprise applications, games, web services, and mobile apps.
C# runs on the .NET framework and .NET Core, providing a robust ecosystem for building cross-platform applications. It combines the power of C++ with the simplicity of Visual Basic and brings modern features like LINQ, async/await, and pattern matching to developers.
Did you know? C# was originally named "Cool" (C-like Object Oriented Language) but was renamed to C# for trademark reasons. The '#' symbol represents four plus signs, indicating it's a step beyond C++.
1. C# Basics & Syntax
Hello World and Basic Structure
using System;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
// Basic output
Console.WriteLine("Hello, World!");
// Input from user
Console.Write("Enter your name: ");
string name = Console.ReadLine();
Console.WriteLine($"Hello, {name}!");
// Command line arguments
if (args.Length > 0)
{
Console.WriteLine($"First argument: {args[0]}");
}
}
}
}
// Modern C# 9.0+ Top-level statements (no namespace/class required)
using System;
Console.WriteLine("Hello, World!");
Console.Write("Enter your name: ");
string name = Console.ReadLine();
Console.WriteLine($"Hello, {name}!");Variables and Data Types
using System;
class DataTypes
{
static void Main()
{
// Value types
int age = 25; // 32-bit integer
long bigNumber = 123456789L; // 64-bit integer
double price = 19.99; // Double-precision floating point
decimal salary = 50000.50M; // Decimal for financial calculations
float temperature = 23.5f; // Single-precision floating point
char grade = 'A'; // Single character
bool isActive = true; // Boolean
// Reference types
string name = "John Doe"; // String
object obj = new object(); // Base object type
dynamic dynamicVar = "Hello"; // Dynamic type (resolved at runtime)
// Nullable value types
int? nullableInt = null; // Can hold null
nullableInt = 42; // Now has value
// Type inference with var
var count = 10; // Compiler infers int
var message = "Hello"; // Compiler infers string
var numbers = new int[] {1, 2, 3}; // Compiler infers int[]
// Constants
const double PI = 3.14159;
const string APP_NAME = "My Application";
// Displaying values
Console.WriteLine($"Name: {name}, Age: {age}");
Console.WriteLine($"Price: {price:C}"); // Currency format
Console.WriteLine($"Temperature: {temperature:F1}°C"); // 1 decimal place
// Type information
Console.WriteLine($"Type of count: {count.GetType()}");
Console.WriteLine($"Type of message: {message.GetType()}");
}
}Operators and Expressions
using System;
class Operators
{
static void Main()
{
// Arithmetic operators
int a = 10, b = 3;
int sum = a + b; // 13
int difference = a - b; // 7
int product = a * b; // 30
int quotient = a / b; // 3 (integer division)
double realQuotient = (double)a / b; // 3.333...
int remainder = a % b; // 1
int increment = a++; // Post-increment: 10 (a becomes 11)
int decrement = --b; // Pre-decrement: 2 (b becomes 2)
// Assignment operators
int x = 10;
x += 5; // x = x + 5 → 15
x -= 3; // x = x - 3 → 12
x *= 2; // x = x * 2 → 24
x /= 4; // x = x / 4 → 6
x %= 5; // x = x % 5 → 1
// Comparison operators
bool isEqual = (a == b); // false
bool notEqual = (a != b); // true
bool greaterThan = (a > b); // true
bool lessOrEqual = (a <= b); // false
// Logical operators
bool condition1 = true, condition2 = false;
bool andResult = condition1 && condition2; // false
bool orResult = condition1 || condition2; // true
bool notResult = !condition1; // false
// Ternary operator
int number = 15;
string result = (number % 2 == 0) ? "Even" : "Odd";
Console.WriteLine($"{number} is {result}");
// Null-coalescing operator
string nullableString = null;
string safeString = nullableString ?? "Default Value";
Console.WriteLine(safeString); // "Default Value"
// Null-conditional operator (C# 6.0+)
string[] names = null;
int? length = names?.Length; // null instead of exception
string first = names?[0]; // null instead of exception
// Bitwise operators
int flags = 5; // Binary: 101
int mask = 3; // Binary: 011
int bitwiseAnd = flags & mask; // 1 (001)
int bitwiseOr = flags | mask; // 7 (111)
int bitwiseXor = flags ^ mask; // 6 (110)
int leftShift = flags << 1; // 10 (1010)
int rightShift = flags >> 1; // 2 (010)
Console.WriteLine($"Bitwise operations: AND={bitwiseAnd}, OR={bitwiseOr}");
}
}Control Flow Statements
using System;
class ControlFlow
{
static void Main()
{
// If-else statements
int temperature = 22;
if (temperature > 30)
{
Console.WriteLine("It's a hot day!");
Console.WriteLine("Stay hydrated!");
}
else if (temperature > 20)
{
Console.WriteLine("Perfect weather!");
Console.WriteLine("Enjoy outdoors!");
}
else
{
Console.WriteLine("It's cold outside!");
Console.WriteLine("Dress warmly!");
}
// Switch statement
string day = "Monday";
switch (day)
{
case "Monday":
Console.WriteLine("Start of the work week");
break;
case "Friday":
Console.WriteLine("Weekend is almost here!");
break;
case "Saturday":
case "Sunday":
Console.WriteLine("Weekend!");
break;
default:
Console.WriteLine("Regular work day");
break;
}
// Switch expression (C# 8.0+)
string message = day switch
{
"Monday" => "Start of week",
"Friday" => "Almost weekend",
"Saturday" or "Sunday" => "Weekend!",
_ => "Regular day"
};
Console.WriteLine(message);
// While loop
int count = 1;
while (count <= 5)
{
Console.WriteLine($"While count: {count}");
count++;
}
// Do-while loop (executes at least once)
int number = 1;
do
{
Console.WriteLine($"Do-while number: {number}");
number++;
} while (number <= 3);
// For loop
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"For iteration: {i}");
}
// Foreach loop
string[] fruits = { "apple", "banana", "orange" };
foreach (string fruit in fruits)
{
Console.WriteLine($"Fruit: {fruit}");
}
// Loop control statements
for (int i = 0; i < 10; i++)
{
if (i == 3)
continue; // Skip this iteration
if (i == 7)
break; // Exit loop
Console.WriteLine($"Number: {i}");
}
// Exception handling with try-catch
try
{
Console.Write("Enter a number: ");
string input = Console.ReadLine();
int parsedNumber = int.Parse(input);
Console.WriteLine($"You entered: {parsedNumber}");
}
catch (FormatException)
{
Console.WriteLine("Invalid number format!");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
Console.WriteLine("This always executes");
}
}
}2. Object-Oriented Programming
Classes and Objects
using System;
namespace OOPBasics
{
// Basic class definition
public class Person
{
// Fields (private by convention)
private string name;
private int age;
// Properties (public interface)
public string Name
{
get { return name; }
set
{
if (!string.IsNullOrWhiteSpace(value))
name = value;
}
}
public int Age
{
get { return age; }
set
{
if (value >= 0 && value <= 150)
age = value;
}
}
// Auto-implemented property
public string Email { get; set; }
// Read-only property
public string DisplayName => $"{Name} ({Age})";
// Constructors
public Person() { }
public Person(string name, int age)
{
Name = name;
Age = age;
}
// Methods
public void Introduce()
{
Console.WriteLine($"Hello, my name is {Name} and I am {Age} years old.");
}
public string GetBirthYear()
{
int currentYear = DateTime.Now.Year;
return $"Born around {currentYear - Age}";
}
// Static method
public static void DisplaySpecies()
{
Console.WriteLine("Species: Homo sapiens");
}
}
class Program
{
static void Main()
{
// Creating objects
Person person1 = new Person();
person1.Name = "John Doe";
person1.Age = 25;
person1.Email = "john@example.com";
Person person2 = new Person("Jane Smith", 30);
// Using methods
person1.Introduce();
person2.Introduce();
// Using properties
Console.WriteLine($"{person1.Name}'s display: {person1.DisplayName}");
Console.WriteLine(person1.GetBirthYear());
// Static method call
Person.DisplaySpecies();
// Object initializer syntax
Person person3 = new Person
{
Name = "Bob Johnson",
Age = 35,
Email = "bob@example.com"
};
person3.Introduce();
}
}
}Inheritance and Polymorphism
using System;
using System.Collections.Generic;
namespace OOPAdvanced
{
// Base class
public abstract class Animal
{
public string Name { get; set; }
public int Age { get; set; }
// Virtual method - can be overridden
public virtual void MakeSound()
{
Console.WriteLine("Some generic animal sound");
}
// Abstract method - must be implemented by derived classes
public abstract void Move();
// Regular method
public void Sleep()
{
Console.WriteLine($"{Name} is sleeping...");
}
}
// Interface
public interface IPet
{
string Owner { get; set; }
void Play();
}
// Derived class
public class Dog : Animal, IPet
{
public string Breed { get; set; }
public string Owner { get; set; }
// Constructor
public Dog(string name, string breed)
{
Name = name;
Breed = breed;
}
// Override virtual method
public override void MakeSound()
{
Console.WriteLine("Woof! Woof!");
}
// Implement abstract method
public override void Move()
{
Console.WriteLine($"{Name} is running on four legs");
}
// Implement interface method
public void Play()
{
Console.WriteLine($"{Name} is playing fetch with {Owner}");
}
// New method specific to Dog
public void WagTail()
{
Console.WriteLine($"{Name} is wagging its tail");
}
}
// Another derived class
public class Cat : Animal, IPet
{
public bool IsIndoor { get; set; }
public string Owner { get; set; }
public override void MakeSound()
{
Console.WriteLine("Meow! Meow!");
}
public override void Move()
{
Console.WriteLine($"{Name} is walking gracefully");
}
public void Play()
{
Console.WriteLine($"{Name} is playing with a ball of yarn");
}
public void Purr()
{
Console.WriteLine($"{Name} is purring...");
}
}
class Program
{
static void Main()
{
// Polymorphism in action
List<Animal> animals = new List<Animal>
{
new Dog("Buddy", "Golden Retriever") { Owner = "John", Age = 3 },
new Cat("Whiskers", true) { Owner = "Jane", Age = 2 }
};
foreach (Animal animal in animals)
{
Console.WriteLine($"\n{animal.Name}:");
animal.MakeSound();
animal.Move();
animal.Sleep();
// Type checking and casting
if (animal is IPet pet)
{
pet.Play();
}
if (animal is Dog dog)
{
dog.WagTail();
}
else if (animal is Cat cat)
{
cat.Purr();
}
}
// Using interface reference
IPet myPet = new Dog("Max", "Labrador") { Owner = "Alice" };
myPet.Play();
}
}
// Sealed class - cannot be inherited
public sealed class FinalClass
{
public string Message { get; set; }
}
// This would cause error:
// public class DerivedClass : FinalClass { }
}Encapsulation and Access Modifiers
using System;
namespace EncapsulationExample
{
public class BankAccount
{
// Private fields - only accessible within this class
private string accountNumber;
private decimal balance;
private string accountHolder;
private DateTime createdDate;
// Public properties with controlled access
public string AccountNumber
{
get { return accountNumber; }
private set { accountNumber = value; }
}
public decimal Balance
{
get { return balance; }
private set { balance = value; }
}
public string AccountHolder
{
get { return accountHolder; }
set
{
if (!string.IsNullOrWhiteSpace(value))
accountHolder = value;
}
}
public DateTime CreatedDate
{
get { return createdDate; }
}
// Read-only property
public bool IsActive => Balance >= 0;
// Constructor
public BankAccount(string accountHolder, string accountNumber, decimal initialDeposit = 0)
{
if (initialDeposit < 0)
throw new ArgumentException("Initial deposit cannot be negative");
AccountHolder = accountHolder;
this.accountNumber = accountNumber;
this.balance = initialDeposit;
this.createdDate = DateTime.Now;
}
// Public methods to manipulate balance
public void Deposit(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("Deposit amount must be positive");
balance += amount;
LogTransaction($"Deposited: {amount:C}");
}
public bool Withdraw(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("Withdrawal amount must be positive");
if (balance >= amount)
{
balance -= amount;
LogTransaction($"Withdrew: {amount:C}");
return true;
}
Console.WriteLine("Insufficient funds!");
return false;
}
public void Transfer(BankAccount targetAccount, decimal amount)
{
if (targetAccount == null)
throw new ArgumentNullException(nameof(targetAccount));
if (Withdraw(amount))
{
targetAccount.Deposit(amount);
LogTransaction($"Transferred: {amount:C} to {targetAccount.AccountNumber}");
}
}
// Private helper method - only accessible within this class
private void LogTransaction(string message)
{
Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}");
Console.WriteLine($"[Balance: {Balance:C}]");
}
// Protected method - accessible within this class and derived classes
protected virtual void OnAccountAction(string action)
{
Console.WriteLine($"Account action: {action}");
}
// Internal method - accessible within the same assembly
internal void InternalMethod()
{
Console.WriteLine("Internal method called");
}
}
// Derived class with additional functionality
public class SavingsAccount : BankAccount
{
private decimal interestRate;
public decimal InterestRate
{
get { return interestRate; }
set
{
if (value >= 0 && value <= 1)
interestRate = value;
}
}
public SavingsAccount(string accountHolder, string accountNumber, decimal interestRate)
: base(accountHolder, accountNumber)
{
InterestRate = interestRate;
}
public void ApplyInterest()
{
decimal interest = Balance * InterestRate;
Deposit(interest);
OnAccountAction($"Interest applied: {interest:C}");
}
// Override protected method
protected override void OnAccountAction(string action)
{
base.OnAccountAction(action);
Console.WriteLine($"Savings Account - {action}");
}
}
class Program
{
static void Main()
{
// Create accounts
BankAccount checking = new BankAccount("John Doe", "CHK12345", 1000);
SavingsAccount savings = new SavingsAccount("John Doe", "SAV67890", 0.02m);
// Test operations
checking.Deposit(500);
checking.Withdraw(200);
checking.Transfer(savings, 300);
savings.ApplyInterest();
// Display account information
Console.WriteLine($"\nChecking Account: {checking.Balance:C}");
Console.WriteLine($"Savings Account: {savings.Balance:C}");
Console.WriteLine($"Checking Active: {checking.IsActive}");
Console.WriteLine($"Account Created: {checking.CreatedDate:yyyy-MM-dd}");
// This would cause errors (private setters):
// checking.Balance = 1000000; // Error!
// checking.AccountNumber = "NEW123"; // Error!
}
}
}3. Data Structures & Collections
Arrays and Strings
using System;
namespace ArraysAndStrings
{
class Program
{
static void Main()
{
// Single-dimensional arrays
int[] numbers = new int[5];
numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;
numbers[4] = 5;
// Array initialization
int[] primes = { 2, 3, 5, 7, 11 };
string[] fruits = { "apple", "banana", "orange" };
// Multi-dimensional arrays
int[,] matrix = new int[3, 3]
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Jagged arrays (array of arrays)
int[][] jagged = new int[3][];
jagged[0] = new int[] {1, 2, 3};
jagged[1] = new int[] {4, 5};
jagged[2] = new int[] {6, 7, 8, 9};
// Array methods and properties
Console.WriteLine($"Array length: {numbers.Length}");
Console.WriteLine($"Array rank: {matrix.Rank}");
Console.WriteLine($"Array dimensions: {matrix.GetLength(0)}x{matrix.GetLength(1)}");
Array.Sort(primes);
Array.Reverse(primes);
int index = Array.IndexOf(primes, 5);
// String basics
string firstName = "John";
string lastName = "Doe";
string fullName = firstName + " " + lastName;
string interpolated = $"{firstName} {lastName}";
string formatted = string.Format("{0} {1}", firstName, lastName);
// String methods
string text = " Hello, World! ";
Console.WriteLine($"Original: '{text}'");
Console.WriteLine($"Trimmed: '{text.Trim()}'");
Console.WriteLine($"Upper: {text.ToUpper()}");
Console.WriteLine($"Lower: {text.ToLower()}");
Console.WriteLine($"Length: {text.Length}");
Console.WriteLine($"Contains 'World': {text.Contains("World")}");
Console.WriteLine($"StartsWith 'Hello': {text.Trim().StartsWith("Hello")}");
Console.WriteLine($"Index of 'World': {text.IndexOf("World")}");
// String splitting and joining
string csv = "apple,banana,orange,grape";
string[] fruitArray = csv.Split(',');
string joined = string.Join(" - ", fruitArray);
Console.WriteLine($"Joined: {joined}");
// String building for efficient concatenation
var sb = new System.Text.StringBuilder();
for (int i = 0; i < 10; i++)
{
sb.Append(i);
sb.Append(" ");
}
string result = sb.ToString();
Console.WriteLine($"StringBuilder result: {result}");
// String comparison
string str1 = "hello";
string str2 = "HELLO";
bool equal1 = str1 == str2; // false
bool equal2 = str1.Equals(str2); // false
bool equal3 = str1.Equals(str2, StringComparison.OrdinalIgnoreCase); // true
Console.WriteLine($"\nString comparisons:");
Console.WriteLine($"== : {equal1}");
Console.WriteLine($"Equals: {equal2}");
Console.WriteLine($"Ignore case: {equal3}");
// String formatting
DateTime now = DateTime.Now;
string dateString = string.Format("Today is {0:yyyy-MM-dd} and time is {0:HH:mm:ss}", now);
Console.WriteLine(dateString);
decimal price = 19.99m;
Console.WriteLine($"Price: {price:C}"); // Currency
Console.WriteLine($"Price: {price:F2}"); // Fixed point
Console.WriteLine($"Large number: {1234567:N0}"); // Number with commas
}
}
}Collections and Generics
using System;
using System.Collections.Generic;
using System.Linq;
namespace CollectionsExample
{
class Program
{
static void Main()
{
// List<T> - Dynamic array
List<string> fruits = new List<string> { "apple", "banana" };
fruits.Add("orange");
fruits.AddRange(new[] { "grape", "mango" });
fruits.Insert(1, "kiwi");
fruits.Remove("banana");
fruits.RemoveAt(0);
Console.WriteLine("List operations:");
foreach (string fruit in fruits)
{
Console.WriteLine($" - {fruit}");
}
Console.WriteLine($"Count: {fruits.Count}");
Console.WriteLine($"Contains 'orange': {fruits.Contains("orange")}");
Console.WriteLine($"Index of 'grape': {fruits.IndexOf("grape")}");
// Dictionary<TKey, TValue> - Key-value pairs
Dictionary<string, int> ages = new Dictionary<string, int>
{
["John"] = 25,
["Jane"] = 30,
["Bob"] = 35
};
ages["Alice"] = 28; // Add or update
ages.TryAdd("Charlie", 40); // Safe add
Console.WriteLine("\nDictionary operations:");
foreach (KeyValuePair<string, int> kvp in ages)
{
Console.WriteLine($" {kvp.Key}: {kvp.Value} years old");
}
if (ages.TryGetValue("John", out int johnsAge))
{
Console.WriteLine($"John's age: {johnsAge}");
}
// HashSet<T> - Unique elements
HashSet<int> uniqueNumbers = new HashSet<int> { 1, 2, 3, 4, 5 };
uniqueNumbers.Add(3); // Won't add duplicate
uniqueNumbers.Add(6); // Will add new
HashSet<int> otherNumbers = new HashSet<int> { 4, 5, 6, 7, 8 };
Console.WriteLine("\nHashSet operations:");
Console.WriteLine($"Union: {string.Join(", ", uniqueNumbers.Union(otherNumbers))}");
Console.WriteLine($"Intersection: {string.Join(", ", uniqueNumbers.Intersect(otherNumbers))}");
Console.WriteLine($"Difference: {string.Join(", ", uniqueNumbers.Except(otherNumbers))}");
// Queue<T> - FIFO (First In First Out)
Queue<string> queue = new Queue<string>();
queue.Enqueue("first");
queue.Enqueue("second");
queue.Enqueue("third");
Console.WriteLine("\nQueue operations:");
while (queue.Count > 0)
{
string item = queue.Dequeue();
Console.WriteLine($"Dequeued: {item}");
}
// Stack<T> - LIFO (Last In First Out)
Stack<string> stack = new Stack<string>();
stack.Push("first");
stack.Push("second");
stack.Push("third");
Console.WriteLine("\nStack operations:");
while (stack.Count > 0)
{
string item = stack.Pop();
Console.WriteLine($"Popped: {item}");
}
// LinkedList<T> - Doubly linked list
LinkedList<string> linkedList = new LinkedList<string>();
linkedList.AddLast("apple");
linkedList.AddLast("banana");
linkedList.AddFirst("orange"); // Becomes first
Console.WriteLine("\nLinkedList operations:");
LinkedListNode<string> currentNode = linkedList.First;
while (currentNode != null)
{
Console.WriteLine($"Node: {currentNode.Value}");
currentNode = currentNode.Next;
}
// Sorted collections
SortedList<string, int> sortedAges = new SortedList<string, int>
{
["Charlie"] = 40,
["Alice"] = 28,
["Bob"] = 35
};
Console.WriteLine("\nSortedList (automatically sorted by key):");
foreach (var kvp in sortedAges)
{
Console.WriteLine($" {kvp.Key}: {kvp.Value}");
}
// Collection initialization with custom objects
List<Person> people = new List<Person>
{
new Person("John", 25),
new Person("Jane", 30),
new Person("Bob", 35)
};
Console.WriteLine("\nCustom objects in collection:");
foreach (Person person in people)
{
Console.WriteLine($" {person.Name} - {person.Age} years");
}
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
}4. Advanced C# Features
Delegates, Events, and Lambdas
using System;
namespace AdvancedFeatures
{
// Delegate declarations
public delegate void SimpleDelegate(string message);
public delegate int MathOperation(int a, int b);
public delegate bool FilterCondition(int number);
public class Calculator
{
// Method that matches MathOperation signature
public static int Add(int a, int b) => a + b;
public static int Multiply(int a, int b) => a * b;
public static int Subtract(int a, int b) => a - b;
}
// Event publisher class
public class Button
{
// Event declaration
public event EventHandler<string> Clicked;
public void Click()
{
Console.WriteLine("Button was clicked!");
OnClicked("Button click event raised");
}
protected virtual void OnClicked(string message)
{
Clicked?.Invoke(this, message);
}
}
public class AdvancedDemo
{
public static void DemonstrateDelegates()
{
Console.WriteLine("=== DELEGATES ===");
// Instantiate delegates
SimpleDelegate simple = PrintMessage;
MathOperation mathOp = Calculator.Add;
// Invoke delegates
simple("Hello from delegate!");
int result = mathOp(10, 5);
Console.WriteLine($"10 + 5 = {result}");
// Multicast delegates
SimpleDelegate multi = PrintMessage;
multi += PrintUpperCase;
multi += (msg) => Console.WriteLine($"Lambda: {msg}");
multi("Multicast demo");
// Change delegate reference
mathOp = Calculator.Multiply;
result = mathOp(10, 5);
Console.WriteLine($"10 * 5 = {result}");
}
public static void DemonstrateEvents()
{
Console.WriteLine("\n=== EVENTS ===");
Button button = new Button();
// Subscribe to event
button.Clicked += (sender, message) =>
{
Console.WriteLine($"Event handled: {message}");
};
button.Clicked += Button_Clicked;
// Trigger event
button.Click();
// Unsubscribe
button.Clicked -= Button_Clicked;
}
private static void Button_Clicked(object sender, string message)
{
Console.WriteLine($"Additional handler: {message}");
}
public static void DemonstrateLambdas()
{
Console.WriteLine("\n=== LAMBDA EXPRESSIONS ===");
// Lambda expressions
MathOperation add = (a, b) => a + b;
MathOperation multiply = (a, b) => a * b;
Console.WriteLine($"Lambda add: {add(7, 3)}");
Console.WriteLine($"Lambda multiply: {multiply(7, 3)}");
// Using built-in Func and Action delegates
Func<int, int, int> funcAdd = (a, b) => a + b;
Action<string> actionPrint = (msg) => Console.WriteLine(msg);
actionPrint($"Func result: {funcAdd(15, 25)}");
// Complex lambda with multiple statements
Func<int, int, string> complex = (a, b) =>
{
int sum = a + b;
return $"The sum of {a} and {b} is {sum}";
};
Console.WriteLine(complex(8, 12));
// Using lambda with collections
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Filter even numbers using lambda
var evenNumbers = Array.FindAll(numbers, n => n % 2 == 0);
Console.WriteLine("Even numbers: " + string.Join(", ", evenNumbers));
// Transform numbers using lambda
var squared = Array.ConvertAll(numbers, n => n * n);
Console.WriteLine("Squared numbers: " + string.Join(", ", squared));
}
public static void DemonstrateAnonymousMethods()
{
Console.WriteLine("\n=== ANONYMOUS METHODS ===");
// Anonymous method (older syntax)
MathOperation oldStyle = delegate(int a, int b)
{
return a + b;
};
Console.WriteLine($"Anonymous method: {oldStyle(20, 30)}");
}
// Method that matches SimpleDelegate signature
public static void PrintMessage(string message)
{
Console.WriteLine($"Message: {message}");
}
public static void PrintUpperCase(string message)
{
Console.WriteLine($"UPPER: {message.ToUpper()}");
}
}
class Program
{
static void Main()
{
AdvancedDemo.DemonstrateDelegates();
AdvancedDemo.DemonstrateEvents();
AdvancedDemo.DemonstrateLambdas();
AdvancedDemo.DemonstrateAnonymousMethods();
}
}
}Extension Methods and Partial Classes
using System;
using System.Collections.Generic;
using System.Text;
namespace ExtensionMethodsDemo
{
// Extension methods must be in static class
public static class StringExtensions
{
// Extension method for string class
public static string Reverse(this string str)
{
if (string.IsNullOrEmpty(str))
return str;
char[] charArray = str.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
public static bool IsPalindrome(this string str)
{
if (string.IsNullOrEmpty(str))
return false;
string clean = str.ToLower().Replace(" ", "");
return clean == clean.Reverse();
}
public static string ToTitleCase(this string str)
{
if (string.IsNullOrEmpty(str))
return str;
string[] words = str.Split(' ');
for (int i = 0; i < words.Length; i++)
{
if (!string.IsNullOrEmpty(words[i]))
{
words[i] = char.ToUpper(words[i][0]) + words[i].Substring(1).ToLower();
}
}
return string.Join(" ", words);
}
}
public static class CollectionExtensions
{
public static void PrintAll<T>(this IEnumerable<T> collection)
{
Console.WriteLine($"[{string.Join(", ", collection)}]");
}
public static string ToDelimitedString<T>(this IEnumerable<T> collection, string delimiter = ", ")
{
return string.Join(delimiter, collection);
}
public static bool IsEmpty<T>(this ICollection<T> collection)
{
return collection.Count == 0;
}
}
public static class NumberExtensions
{
public static bool IsEven(this int number) => number % 2 == 0;
public static bool IsOdd(this int number) => number % 2 != 0;
public static bool IsPrime(this int number)
{
if (number <= 1) return false;
if (number == 2) return true;
if (number % 2 == 0) return false;
for (int i = 3; i * i <= number; i += 2)
{
if (number % i == 0)
return false;
}
return true;
}
public static int Squared(this int number) => number * number;
public static double ToRadians(this double degrees) => degrees * Math.PI / 180;
public static double ToDegrees(this double radians) => radians * 180 / Math.PI;
}
// Partial class example - split across multiple files
public partial class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public decimal Salary { get; set; }
public Employee(string firstName, string lastName, decimal salary)
{
FirstName = firstName;
LastName = lastName;
Salary = salary;
}
// Partial method declaration (must be void)
partial void OnSalaryChanged(decimal oldSalary, decimal newSalary);
public void RaiseSalary(decimal amount)
{
decimal oldSalary = Salary;
Salary += amount;
OnSalaryChanged(oldSalary, Salary); // Call partial method
}
}
// Second part of partial class (could be in separate file)
public partial class Employee
{
public string FullName => $"{FirstName} {LastName}";
public string GetInfo()
{
return $"{FullName} - Salary: {Salary:C}";
}
// Implementation of partial method
partial void OnSalaryChanged(decimal oldSalary, decimal newSalary)
{
Console.WriteLine($"Salary changed from {oldSalary:C} to {newSalary:C}");
}
// Additional methods
public void DisplayEmployee()
{
Console.WriteLine(GetInfo());
}
}
class Program
{
static void Main()
{
Console.WriteLine("=== EXTENSION METHODS ===");
// Using string extensions
string text = "Hello World";
Console.WriteLine($"Original: {text}");
Console.WriteLine($"Reversed: {text.Reverse()}");
Console.WriteLine($"Title Case: {text.ToTitleCase()}");
Console.WriteLine($"Is Palindrome 'radar': {"radar".IsPalindrome()}");
Console.WriteLine($"Is Palindrome 'hello': {"hello".IsPalindrome()}");
// Using collection extensions
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
Console.WriteLine("\nCollection extensions:");
numbers.PrintAll();
Console.WriteLine($"Delimited: {numbers.ToDelimitedString(" | ")}");
Console.WriteLine($"Is empty: {numbers.IsEmpty()}");
// Using number extensions
int testNumber = 17;
Console.WriteLine("\nNumber extensions:");
Console.WriteLine($"{testNumber} is even: {testNumber.IsEven()}");
Console.WriteLine($"{testNumber} is odd: {testNumber.IsOdd()}");
Console.WriteLine($"{testNumber} is prime: {testNumber.IsPrime()}");
Console.WriteLine($"{testNumber} squared: {testNumber.Squared()}");
// Using partial class
Console.WriteLine("\n=== PARTIAL CLASS ===");
Employee emp = new Employee("John", "Doe", 50000);
emp.DisplayEmployee();
emp.RaiseSalary(10000);
emp.DisplayEmployee();
// Real-world example: Building a query with extensions
Console.WriteLine("\n=== PRACTICAL EXAMPLE ===");
var primes = new List<int>();
for (int i = 1; i <= 20; i++)
{
if (i.IsPrime())
primes.Add(i);
}
Console.WriteLine($"Primes 1-20: {primes.ToDelimitedString()}");
}
}
}5. LINQ & Functional Programming
LINQ Fundamentals
using System;
using System.Collections.Generic;
using System.Linq;
namespace LINQFundamentals
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
public int Stock { get; set; }
public override string ToString() => $"{Name} ({Category}) - {Price:C}";
}
class Program
{
static void Main()
{
// Sample data
List<Product> products = new List<Product>
{
new Product { Id = 1, Name = "Laptop", Category = "Electronics", Price = 999.99m, Stock = 10 },
new Product { Id = 2, Name = "Mouse", Category = "Electronics", Price = 25.50m, Stock = 50 },
new Product { Id = 3, Name = "Desk", Category = "Furniture", Price = 299.99m, Stock = 5 },
new Product { Id = 4, Name = "Chair", Category = "Furniture", Price = 149.99m, Stock = 15 },
new Product { Id = 5, Name = "Monitor", Category = "Electronics", Price = 199.99m, Stock = 8 },
new Product { Id = 6, Name = "Keyboard", Category = "Electronics", Price = 75.00m, Stock = 25 },
new Product { Id = 7, Name = "Bookshelf", Category = "Furniture", Price = 179.99m, Stock = 3 },
new Product { Id = 8, Name = "Tablet", Category = "Electronics", Price = 349.99m, Stock = 12 }
};
// LINQ Query Syntax
Console.WriteLine("=== QUERY SYNTAX ===");
// Basic filtering
var expensiveProducts = from p in products
where p.Price > 100
select p;
Console.WriteLine("Products over $100:");
foreach (var product in expensiveProducts)
{
Console.WriteLine($" - {product}");
}
// Filtering and ordering
var electronicsByPrice = from p in products
where p.Category == "Electronics"
orderby p.Price descending
select p;
Console.WriteLine("\nElectronics by price (descending):");
foreach (var product in electronicsByPrice)
{
Console.WriteLine($" - {product}");
}
// Grouping
var productsByCategory = from p in products
group p by p.Category into categoryGroup
select new
{
Category = categoryGroup.Key,
Count = categoryGroup.Count(),
TotalValue = categoryGroup.Sum(p => p.Price * p.Stock)
};
Console.WriteLine("\nProducts by category:");
foreach (var group in productsByCategory)
{
Console.WriteLine($" {group.Category}: {group.Count} products, Total value: {group.TotalValue:C}");
}
// Joining (if we had another collection)
var categories = new List<string> { "Electronics", "Furniture", "Clothing" };
var categoryProducts = from c in categories
join p in products on c equals p.Category into productGroup
select new
{
Category = c,
Products = productGroup
};
Console.WriteLine("\nProducts by category (with join):");
foreach (var item in categoryProducts)
{
Console.WriteLine($"\n{item.Category}:");
foreach (var product in item.Products)
{
Console.WriteLine($" - {product.Name}");
}
}
// LINQ Method Syntax
Console.WriteLine("\n=== METHOD SYNTAX ===");
// Basic filtering
var cheapProducts = products.Where(p => p.Price < 100);
Console.WriteLine("Products under $100:");
cheapProducts.ToList().ForEach(p => Console.WriteLine($" - {p}"));
// Complex queries
var lowStockElectronics = products
.Where(p => p.Category == "Electronics" && p.Stock < 15)
.OrderBy(p => p.Stock)
.Select(p => new { p.Name, p.Stock, p.Price });
Console.WriteLine("\nLow stock electronics:");
foreach (var item in lowStockElectronics)
{
Console.WriteLine($" - {item.Name}: {item.Stock} in stock, {item.Price:C}");
}
// Aggregation methods
Console.WriteLine("\n=== AGGREGATION ===");
decimal totalValue = products.Sum(p => p.Price * p.Stock);
decimal averagePrice = products.Average(p => p.Price);
decimal maxPrice = products.Max(p => p.Price);
decimal minPrice = products.Min(p => p.Price);
int totalProducts = products.Count();
Console.WriteLine($"Total inventory value: {totalValue:C}");
Console.WriteLine($"Average price: {averagePrice:C}");
Console.WriteLine($"Max price: {maxPrice:C}");
Console.WriteLine($"Min price: {minPrice:C}");
Console.WriteLine($"Total products: {totalProducts}");
// Element operations
Console.WriteLine("\n=== ELEMENT OPERATIONS ===");
Product firstProduct = products.First();
Product lastProduct = products.Last();
Product singleElectronics = products.First(p => p.Category == "Electronics");
Product maybeProduct = products.FirstOrDefault(p => p.Price > 1000);
Console.WriteLine($"First product: {firstProduct}");
Console.WriteLine($"Last product: {lastProduct}");
Console.WriteLine($"First electronics: {singleElectronics}");
Console.WriteLine($"Product over $1000: {(maybeProduct?.ToString() ?? "None")}");
// Set operations
Console.WriteLine("\n=== SET OPERATIONS ===");
List<string> categories1 = new List<string> { "A", "B", "C" };
List<string> categories2 = new List<string> { "B", "C", "D" };
var union = categories1.Union(categories2);
var intersect = categories1.Intersect(categories2);
var except = categories1.Except(categories2);
Console.WriteLine($"Union: {string.Join(", ", union)}");
Console.WriteLine($"Intersection: {string.Join(", ", intersect)}");
Console.WriteLine($"Difference: {string.Join(", ", except)}");
// Partitioning
Console.WriteLine("\n=== PARTITIONING ===");
var firstThree = products.Take(3);
var skipFirstThree = products.Skip(3);
var page2 = products.Skip(3).Take(3);
Console.WriteLine("First 3 products:");
firstThree.ToList().ForEach(p => Console.WriteLine($" - {p}"));
Console.WriteLine("\nProducts after skipping first 3:");
skipFirstThree.ToList().ForEach(p => Console.WriteLine($" - {p}"));
// Quantifiers
Console.WriteLine("\n=== QUANTIFIERS ===");
bool hasExpensive = products.Any(p => p.Price > 500);
bool allHaveStock = products.All(p => p.Stock > 0);
bool containsLaptop = products.Any(p => p.Name == "Laptop");
Console.WriteLine($"Has expensive products: {hasExpensive}");
Console.WriteLine($"All products have stock: {allHaveStock}");
Console.WriteLine($"Contains laptop: {containsLaptop}");
}
}
}Advanced LINQ and Performance
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
namespace AdvancedLINQ
{
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Major { get; set; }
public double GPA { get; set; }
public List<string> Courses { get; set; }
public Student(int id, string name, int age, string major, double gpa)
{
Id = id;
Name = name;
Age = age;
Major = major;
GPA = gpa;
Courses = new List<string>();
}
public override string ToString() => $"{Name} ({Major}) - GPA: {GPA:F2}";
}
class Program
{
static void Main()
{
var students = new List<Student>
{
new Student(1, "Alice", 20, "Computer Science", 3.8) { Courses = { "C#", "Algorithms", "Database" } },
new Student(2, "Bob", 22, "Mathematics", 3.2) { Courses = { "Calculus", "Statistics", "C#" } },
new Student(3, "Charlie", 21, "Physics", 3.9) { Courses = { "Physics", "Calculus", "Programming" } },
new Student(4, "Diana", 19, "Computer Science", 3.5) { Courses = { "C#", "Web Development", "Database" } },
new Student(5, "Eve", 23, "Mathematics", 3.7) { Courses = { "Statistics", "Algebra", "C#" } },
new Student(6, "Frank", 20, "Physics", 3.1) { Courses = { "Physics", "Calculus", "Chemistry" } },
new Student(7, "Grace", 22, "Computer Science", 3.9) { Courses = { "C#", "Algorithms", "AI" } }
};
// Deferred Execution vs Immediate Execution
Console.WriteLine("=== DEFERRED EXECUTION ===");
// This query is not executed yet
var deferredQuery = students.Where(s => s.GPA > 3.5)
.OrderByDescending(s => s.GPA)
.Select(s => new { s.Name, s.GPA });
Console.WriteLine("Query defined but not executed yet");
// Execution happens here (when we iterate)
Console.WriteLine("Executing query:");
foreach (var student in deferredQuery)
{
Console.WriteLine($" - {student.Name}: {student.GPA:F2}");
}
// Immediate execution with ToList(), ToArray(), etc.
var immediateResult = students.Where(s => s.Major == "Computer Science")
.ToList(); // Executes immediately
Console.WriteLine($"\nImmediate execution - CS students: {immediateResult.Count}");
// Complex queries with multiple from clauses (SelectMany)
Console.WriteLine("\n=== SELECTMANY (FLATTENING) ===");
var allCourses = students.SelectMany(s => s.Courses)
.Distinct()
.OrderBy(course => course);
Console.WriteLine("All unique courses:");
foreach (var course in allCourses)
{
Console.WriteLine($" - {course}");
}
// Students and their courses
var studentCourses = from student in students
from course in student.Courses
select new { student.Name, Course = course };
Console.WriteLine("\nStudents and their courses:");
foreach (var item in studentCourses.Take(5)) // Show first 5
{
Console.WriteLine($" - {item.Name} takes {item.Course}");
}
// GroupJoin (like SQL LEFT JOIN)
Console.WriteLine("\n=== GROUPJOIN ===");
var majors = new List<string> { "Computer Science", "Mathematics", "Physics", "Chemistry" };
var studentsByMajor = from major in majors
join student in students on major equals student.Major into studentGroup
select new
{
Major = major,
Students = studentGroup,
Count = studentGroup.Count(),
AverageGPA = studentGroup.Any() ? studentGroup.Average(s => s.GPA) : 0
};
foreach (var group in studentsByMajor)
{
Console.WriteLine($"\n{group.Major}:");
Console.WriteLine($" Count: {group.Count}, Average GPA: {group.AverageGPA:F2}");
foreach (var student in group.Students)
{
Console.WriteLine($" - {student.Name} ({student.GPA:F2})");
}
}
// Let clause for intermediate results
Console.WriteLine("\n=== LET CLAUSE ===");
var studentAnalysis = from student in students
let grade = student.GPA >= 3.7 ? "A" :
student.GPA >= 3.3 ? "B" :
student.GPA >= 2.7 ? "C" : "D"
let status = student.Age >= 21 ? "Senior" : "Junior"
select new
{
student.Name,
student.Age,
student.GPA,
Grade = grade,
Status = status
};
foreach (var analysis in studentAnalysis)
{
Console.WriteLine($"{analysis.Name} ({analysis.Status}, Age {analysis.Age}): GPA {analysis.GPA:F2} -> {analysis.Grade}");
}
// Performance considerations
Console.WriteLine("\n=== PERFORMANCE ===");
var largeList = Enumerable.Range(1, 1000000).ToList();
var stopwatch = Stopwatch.StartNew();
// Inefficient: Multiple iterations
var evenNumbers = largeList.Where(x => x % 2 == 0);
var squared = evenNumbers.Select(x => x * x);
var result1 = squared.ToList();
stopwatch.Stop();
Console.WriteLine($"Multiple operations: {stopwatch.ElapsedMilliseconds}ms");
stopwatch.Restart();
// Efficient: Chained operations
var result2 = largeList.Where(x => x % 2 == 0)
.Select(x => x * x)
.ToList();
stopwatch.Stop();
Console.WriteLine($"Chained operations: {stopwatch.ElapsedMilliseconds}ms");
// PLINQ (Parallel LINQ)
Console.WriteLine("\n=== PLINQ (PARALLEL LINQ) ===");
stopwatch.Restart();
var sequential = largeList.Where(x => x % 2 == 0)
.Select(x => x * x)
.ToList();
stopwatch.Stop();
Console.WriteLine($"Sequential: {stopwatch.ElapsedMilliseconds}ms");
stopwatch.Restart();
var parallel = largeList.AsParallel()
.Where(x => x % 2 == 0)
.Select(x => x * x)
.ToList();
stopwatch.Stop();
Console.WriteLine($"Parallel: {stopwatch.ElapsedMilliseconds}ms");
// Custom LINQ methods
Console.WriteLine("\n=== CUSTOM LINQ METHODS ===");
var topStudents = students.Where(s => s.GPA > 3.5)
.OrderByDescending(s => s.GPA)
.Take(3);
Console.WriteLine("Top 3 students:");
foreach (var student in topStudents)
{
Console.WriteLine($" - {student}");
}
// Pagination example
int pageSize = 2;
int pageNumber = 2;
var page = students.OrderBy(s => s.Name)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize);
Console.WriteLine($"\nPage {pageNumber} (size {pageSize}):");
foreach (var student in page)
{
Console.WriteLine($" - {student.Name}");
}
}
}
}6. Async Programming
Async/Await Fundamentals
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
namespace AsyncProgramming
{
public class AsyncDemo
{
// Basic async method
public static async Task<string> DownloadWebsiteAsync(string url)
{
using (var client = new HttpClient())
{
Console.WriteLine($"Starting download from {url}");
string content = await client.GetStringAsync(url);
Console.WriteLine($"Download completed from {url}");
return content;
}
}
// Async method with return value
public static async Task<int> CalculateFactorialAsync(int n)
{
Console.WriteLine($"Starting factorial calculation for {n}");
// Simulate CPU-bound work
await Task.Run(() =>
{
for (int i = 1; i <= n; i++)
{
// Simulate work
Task.Delay(10).Wait();
}
});
int result = 1;
for (int i = 2; i <= n; i++)
{
result *= i;
}
Console.WriteLine($"Factorial calculation completed for {n}");
return result;
}
// Multiple async operations
public static async Task<List<string>> DownloadMultipleWebsitesAsync(List<string> urls)
{
var tasks = new List<Task<string>>();
foreach (string url in urls)
{
tasks.Add(DownloadWebsiteAsync(url));
}
Console.WriteLine("All download tasks started...");
// Wait for all downloads to complete
string[] results = await Task.WhenAll(tasks);
Console.WriteLine("All downloads completed!");
return new List<string>(results);
}
// Async method with exception handling
public static async Task<string> SafeDownloadAsync(string url)
{
try
{
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromSeconds(10);
return await client.GetStringAsync(url);
}
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Network error: {ex.Message}");
return null;
}
catch (TaskCanceledException ex)
{
Console.WriteLine($"Request timeout: {ex.Message}");
return null;
}
}
// Async file operations
public static async Task WriteToFileAsync(string filePath, string content)
{
Console.WriteLine($"Starting file write to {filePath}");
// Ensure directory exists
string directory = Path.GetDirectoryName(filePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
await File.WriteAllTextAsync(filePath, content);
Console.WriteLine($"File write completed: {filePath}");
}
public static async Task<string> ReadFromFileAsync(string filePath)
{
if (!File.Exists(filePath))
{
throw new FileNotFoundException($"File not found: {filePath}");
}
Console.WriteLine($"Starting file read from {filePath}");
string content = await File.ReadAllTextAsync(filePath);
Console.WriteLine($"File read completed: {filePath}");
return content;
}
// Cancellation support
public static async Task LongRunningOperationAsync(
int durationSeconds,
System.Threading.CancellationToken cancellationToken = default)
{
Console.WriteLine($"Starting long operation for {durationSeconds} seconds");
for (int i = 1; i <= durationSeconds; i++)
{
// Check for cancellation
cancellationToken.ThrowIfCancellationRequested();
Console.WriteLine($"Progress: {i}/{durationSeconds} seconds");
await Task.Delay(1000, cancellationToken);
}
Console.WriteLine("Long operation completed!");
}
// Async properties and constructors (not allowed)
// public async string AsyncProperty { get; set; } // Error!
// Async event handlers
public static async void ProcessButtonClick(object sender, EventArgs e)
{
try
{
Console.WriteLine("Button clicked - starting async processing");
await DownloadWebsiteAsync("https://example.com");
Console.WriteLine("Button click processing completed");
}
catch (Exception ex)
{
Console.WriteLine($"Error in button click: {ex.Message}");
}
}
}
// Async repository pattern
public interface IUserRepository
{
Task<User> GetUserByIdAsync(int id);
Task<List<User>> GetAllUsersAsync();
Task AddUserAsync(User user);
Task UpdateUserAsync(User user);
Task DeleteUserAsync(int id);
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
public class MockUserRepository : IUserRepository
{
private readonly List<User> _users = new List<User>
{
new User { Id = 1, Name = "Alice", Email = "alice@example.com" },
new User { Id = 2, Name = "Bob", Email = "bob@example.com" },
new User { Id = 3, Name = "Charlie", Email = "charlie@example.com" }
};
public async Task<User> GetUserByIdAsync(int id)
{
Console.WriteLine($"Getting user {id} from repository");
// Simulate database access delay
await Task.Delay(100);
return _users.Find(u => u.Id == id);
}
public async Task<List<User>> GetAllUsersAsync()
{
Console.WriteLine("Getting all users from repository");
await Task.Delay(200);
return new List<User>(_users);
}
public async Task AddUserAsync(User user)
{
Console.WriteLine($"Adding user: {user.Name}");
await Task.Delay(150);
_users.Add(user);
}
public async Task UpdateUserAsync(User user)
{
Console.WriteLine($"Updating user: {user.Name}");
await Task.Delay(150);
var existingUser = _users.Find(u => u.Id == user.Id);
if (existingUser != null)
{
existingUser.Name = user.Name;
existingUser.Email = user.Email;
}
}
public async Task DeleteUserAsync(int id)
{
Console.WriteLine($"Deleting user {id}");
await Task.Delay(100);
_users.RemoveAll(u => u.Id == id);
}
}
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("=== ASYNC/AWAIT DEMONSTRATION ===\n");
// Basic async call
Console.WriteLine("1. Basic async download:");
string content = await AsyncDemo.DownloadWebsiteAsync("https://httpbin.org/json");
Console.WriteLine($"Downloaded {content?.Length ?? 0} characters\n");
// Multiple async operations
Console.WriteLine("2. Multiple async operations:");
var urls = new List<string>
{
"https://httpbin.org/delay/1",
"https://httpbin.org/delay/2",
"https://httpbin.org/delay/1"
};
var results = await AsyncDemo.DownloadMultipleWebsitesAsync(urls);
Console.WriteLine($"Downloaded {results.Count} websites\n");
// Async with cancellation
Console.WriteLine("3. Async with cancellation:");
using (var cts = new System.Threading.CancellationTokenSource())
{
// Cancel after 3 seconds
cts.CancelAfter(3000);
try
{
await AsyncDemo.LongRunningOperationAsync(5, cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation was cancelled!\n");
}
}
// File operations
Console.WriteLine("4. Async file operations:");
string testFile = "test.txt";
await AsyncDemo.WriteToFileAsync(testFile, "Hello, async file operations!");
string fileContent = await AsyncDemo.ReadFromFileAsync(testFile);
Console.WriteLine($"File content: {fileContent}\n");
// Repository pattern
Console.WriteLine("5. Async repository pattern:");
IUserRepository userRepo = new MockUserRepository();
var users = await userRepo.GetAllUsersAsync();
Console.WriteLine($"Retrieved {users.Count} users");
var user = await userRepo.GetUserByIdAsync(1);
Console.WriteLine($"Retrieved user: {user?.Name}\n");
// ValueTask example for performance
Console.WriteLine("6. ValueTask for high-performance scenarios:");
await UseValueTaskExample();
Console.WriteLine("\nAll async operations completed!");
}
static async ValueTask UseValueTaskExample()
{
// ValueTask is more efficient for synchronous completion
var result = await GetCachedValueAsync();
Console.WriteLine($"ValueTask result: {result}");
}
static async ValueTask<int> GetCachedValueAsync()
{
// If we have cached value, return synchronously
if (DateTime.Now.Second % 2 == 0) // Simple cache simulation
{
return 42; // Synchronous completion
}
// Otherwise, perform async operation
await Task.Delay(100);
return 100;
}
}
}Advanced Async Patterns
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
using System.Linq;
namespace AdvancedAsyncPatterns
{
// Async disposable pattern
public class AsyncResource : IAsyncDisposable
{
private bool _disposed = false;
public async Task ProcessDataAsync()
{
Console.WriteLine("Processing data asynchronously...");
await Task.Delay(1000);
Console.WriteLine("Data processing completed");
}
public async ValueTask DisposeAsync()
{
if (!_disposed)
{
Console.WriteLine("Disposing async resources...");
await Task.Delay(500); // Simulate async cleanup
_disposed = true;
Console.WriteLine("Async disposal completed");
}
}
}
// Async lazy initialization
public class AsyncLazy<T>
{
private readonly Func<Task<T>> _factory;
private Lazy<Task<T>> _lazyTask;
public AsyncLazy(Func<Task<T>> factory)
{
_factory = factory;
_lazyTask = new Lazy<Task<T>>(() => _factory());
}
public Task<T> Value => _lazyTask.Value;
public bool IsValueCreated => _lazyTask.IsValueCreated;
}
// Async event with semaphore for thread safety
public class AsyncEventPublisher
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
private event Func<string, Task> AsyncEvent;
public async Task SubscribeAsync(Func<string, Task> handler)
{
await _semaphore.WaitAsync();
try
{
AsyncEvent += handler;
}
finally
{
_semaphore.Release();
}
}
public async Task UnsubscribeAsync(Func<string, Task> handler)
{
await _semaphore.WaitAsync();
try
{
AsyncEvent -= handler;
}
finally
{
_semaphore.Release();
}
}
public async Task PublishAsync(string message)
{
Func<string, Task> handlers;
await _semaphore.WaitAsync();
try
{
handlers = AsyncEvent;
}
finally
{
_semaphore.Release();
}
if (handlers != null)
{
var invocationTasks = handlers.GetInvocationList()
.Cast<Func<string, Task>>()
.Select(handler => handler(message));
await Task.WhenAll(invocationTasks);
}
}
}
// Async producer-consumer pattern
public class AsyncProducerConsumer<T>
{
private readonly Queue<T> _queue = new Queue<T>();
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(0);
private readonly object _lock = new object();
private bool _completed = false;
public void Produce(T item)
{
lock (_lock)
{
if (_completed)
throw new InvalidOperationException("Production completed");
_queue.Enqueue(item);
_semaphore.Release();
}
}
public async Task<T> ConsumeAsync(CancellationToken cancellationToken = default)
{
await _semaphore.WaitAsync(cancellationToken);
lock (_lock)
{
return _queue.Dequeue();
}
}
public void Complete()
{
lock (_lock)
{
_completed = true;
}
}
}
// Async streams (IAsyncEnumerable) - C# 8.0+
public static class AsyncStreams
{
public static async IAsyncEnumerable<int> GenerateNumbersAsync(int count)
{
for (int i = 1; i <= count; i++)
{
await Task.Delay(100); // Simulate async work
yield return i;
}
}
public static async IAsyncEnumerable<string> SimulateDataStreamAsync()
{
var dataPoints = new[] { "A", "B", "C", "D", "E" };
foreach (var point in dataPoints)
{
await Task.Delay(200); // Simulate async data arrival
yield return point;
}
}
public static async Task ProcessStreamAsync()
{
await foreach (var number in GenerateNumbersAsync(5))
{
Console.WriteLine($"Received: {number}");
}
}
}
// Task completion source for custom async operations
public class AsyncOperation<T>
{
private readonly TaskCompletionSource<T> _tcs = new TaskCompletionSource<T>();
public Task<T> Task => _tcs.Task;
public void SetResult(T result) => _tcs.SetResult(result);
public void SetException(Exception exception) => _tcs.SetException(exception);
public void SetCanceled() => _tcs.SetCanceled();
}
// Retry pattern with exponential backoff
public static class RetryHelper
{
public static async Task<T> RetryAsync<T>(
Func<Task<T>> operation,
int maxRetries = 3,
TimeSpan initialDelay = default,
Func<Exception, bool> shouldRetry = null)
{
if (initialDelay == default)
initialDelay = TimeSpan.FromSeconds(1);
var exceptions = new List<Exception>();
for (int retryCount = 0; retryCount <= maxRetries; retryCount++)
{
try
{
return await operation();
}
catch (Exception ex) when (shouldRetry?.Invoke(ex) ?? true)
{
exceptions.Add(ex);
if (retryCount == maxRetries)
break;
TimeSpan delay = TimeSpan.FromSeconds(Math.Pow(2, retryCount)) + initialDelay;
Console.WriteLine($"Retry {retryCount + 1}/{maxRetries} after {delay}");
await Task.Delay(delay);
}
}
throw new AggregateException("Operation failed after all retries", exceptions);
}
}
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("=== ADVANCED ASYNC PATTERNS ===\n");
// Async disposable
Console.WriteLine("1. Async Disposable Pattern:");
await using (var resource = new AsyncResource())
{
await resource.ProcessDataAsync();
}
Console.WriteLine();
// Async lazy
Console.WriteLine("2. Async Lazy Initialization:");
var lazyValue = new AsyncLazy<string>(async () =>
{
Console.WriteLine("Computing lazy value...");
await Task.Delay(1000);
return "Lazy result";
});
Console.WriteLine("Accessing lazy value...");
string result = await lazyValue.Value;
Console.WriteLine($"Lazy value: {result}\n");
// Async streams
Console.WriteLine("3. Async Streams:");
await foreach (var item in AsyncStreams.GenerateNumbersAsync(3))
{
Console.WriteLine($"Stream item: {item}");
}
Console.WriteLine();
// Producer-consumer pattern
Console.WriteLine("4. Async Producer-Consumer:");
var producerConsumer = new AsyncProducerConsumer<int>();
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
_ = Task.Run(async () =>
{
for (int i = 1; i <= 3; i++)
{
await Task.Delay(500);
producerConsumer.Produce(i);
Console.WriteLine($"Produced: {i}");
}
producerConsumer.Complete();
});
try
{
while (true)
{
var item = await producerConsumer.ConsumeAsync(cts.Token);
Console.WriteLine($"Consumed: {item}");
}
}
catch (OperationCanceledException)
{
Console.WriteLine("Consumption cancelled\n");
}
// Retry pattern
Console.WriteLine("5. Retry Pattern with Exponential Backoff:");
int attempt = 0;
var retryResult = await RetryHelper.RetryAsync(async () =>
{
attempt++;
Console.WriteLine($"Attempt {attempt}");
if (attempt < 3)
{
throw new InvalidOperationException($"Simulated failure {attempt}");
}
await Task.Delay(100);
return "Success!";
}, maxRetries: 3);
Console.WriteLine($"Retry result: {retryResult}\n");
// Task composition
Console.WriteLine("6. Advanced Task Composition:");
await TaskCompositionExamples();
Console.WriteLine("All advanced async patterns demonstrated!");
}
static async Task TaskCompositionExamples()
{
var tasks = new[]
{
Task.Delay(1000).ContinueWith(_ => "First"),
Task.Delay(500).ContinueWith(_ => "Second"),
Task.Delay(1500).ContinueWith(_ => "Third")
};
// Wait for all tasks
var allResults = await Task.WhenAll(tasks);
Console.WriteLine($"WhenAll results: {string.Join(", ", allResults)}");
// Wait for any task
var firstResult = await Task.WhenAny(tasks);
Console.WriteLine($"WhenAny first result: {await firstResult}");
// ContinueWith for task chaining
var complexTask = Task.Run(() => 10)
.ContinueWith(t => t.Result * 2)
.ContinueWith(t => $"Result: {t.Result}")
.ContinueWith(t => t.Result.ToUpper());
Console.WriteLine($"Chained task result: {await complexTask}");
}
}
}7. Web Development with ASP.NET
ASP.NET Core Web API
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Collections.Generic;
using System.Text.Json;
// Minimal API example (ASP.NET Core 6.0+)
var builder = WebApplication.CreateBuilder(args);
// Add services to the container
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
// In-memory data store
var users = new List<User>
{
new User(1, "John Doe", "john@example.com"),
new User(2, "Jane Smith", "jane@example.com"),
new User(3, "Bob Johnson", "bob@example.com")
};
// API endpoints using minimal APIs
app.MapGet("/api/users", () => Results.Ok(users));
app.MapGet("/api/users/{id}", (int id) =>
{
var user = users.Find(u => u.Id == id);
return user != null ? Results.Ok(user) : Results.NotFound();
});
app.MapPost("/api/users", (User user) =>
{
user.Id = users.Count > 0 ? users.Max(u => u.Id) + 1 : 1;
users.Add(user);
return Results.Created($"/api/users/{user.Id}", user);
});
app.MapPut("/api/users/{id}", (int id, User updatedUser) =>
{
var existingUser = users.Find(u => u.Id == id);
if (existingUser == null)
return Results.NotFound();
existingUser.Name = updatedUser.Name;
existingUser.Email = updatedUser.Email;
return Results.Ok(existingUser);
});
app.MapDelete("/api/users/{id}", (int id) =>
{
var user = users.Find(u => u.Id == id);
if (user == null)
return Results.NotFound();
users.Remove(user);
return Results.NoContent();
});
// Health check endpoint
app.MapGet("/health", () => new { status = "Healthy", timestamp = DateTime.UtcNow });
// File upload endpoint
app.MapPost("/api/upload", async (HttpRequest request) =>
{
if (!request.HasFormContentType)
return Results.BadRequest("Expected form data");
var form = await request.ReadFormAsync();
var file = form.Files["file"];
if (file == null || file.Length == 0)
return Results.BadRequest("No file uploaded");
// Process the file
var fileInfo = new
{
FileName = file.FileName,
ContentType = file.ContentType,
Size = file.Length,
UploadedAt = DateTime.UtcNow
};
return Results.Ok(fileInfo);
});
app.Run();
// Record type for immutable data (C# 9.0+)
public record User(int Id, string Name, string Email);
// Traditional Controller-based API (for comparison)
/*
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private static readonly List<User> _users = new();
[HttpGet]
public IActionResult GetUsers() => Ok(_users);
[HttpGet("{id}")]
public IActionResult GetUser(int id)
{
var user = _users.Find(u => u.Id == id);
return user != null ? Ok(user) : NotFound();
}
[HttpPost]
public IActionResult CreateUser(User user)
{
user.Id = _users.Count > 0 ? _users.Max(u => u.Id) + 1 : 1;
_users.Add(user);
return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
}
[HttpPut("{id}")]
public IActionResult UpdateUser(int id, User updatedUser)
{
var existingUser = _users.Find(u => u.Id == id);
if (existingUser == null)
return NotFound();
existingUser.Name = updatedUser.Name;
existingUser.Email = updatedUser.Email;
return Ok(existingUser);
}
[HttpDelete("{id}")]
public IActionResult DeleteUser(int id)
{
var user = _users.Find(u => u.Id == id);
if (user == null)
return NotFound();
_users.Remove(user);
return NoContent();
}
}
*/MVC Pattern and Razor Pages
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
// MVC Controller example
[Route("products")]
public class ProductsController : Controller
{
private readonly IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
[HttpGet]
public async Task<IActionResult> Index(string category = null, int page = 1)
{
var products = await _productService.GetProductsAsync(category, page, 10);
var categories = await _productService.GetCategoriesAsync();
var viewModel = new ProductIndexViewModel
{
Products = products,
Categories = categories,
SelectedCategory = category,
CurrentPage = page
};
return View(viewModel);
}
[HttpGet("{id}")]
public async Task<IActionResult> Details(int id)
{
var product = await _productService.GetProductByIdAsync(id);
if (product == null)
return NotFound();
return View(product);
}
[HttpGet("create")]
public IActionResult Create()
{
return View(new ProductCreateModel());
}
[HttpPost("create")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(ProductCreateModel model)
{
if (!ModelState.IsValid)
return View(model);
var product = new Product
{
Name = model.Name,
Description = model.Description,
Price = model.Price,
Category = model.Category
};
await _productService.CreateProductAsync(product);
return RedirectToAction(nameof(Index));
}
[HttpGet("edit/{id}")]
public async Task<IActionResult> Edit(int id)
{
var product = await _productService.GetProductByIdAsync(id);
if (product == null)
return NotFound();
var model = new ProductEditModel
{
Id = product.Id,
Name = product.Name,
Description = product.Description,
Price = product.Price,
Category = product.Category
};
return View(model);
}
[HttpPost("edit/{id}")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, ProductEditModel model)
{
if (id != model.Id)
return BadRequest();
if (!ModelState.IsValid)
return View(model);
var product = await _productService.GetProductByIdAsync(id);
if (product == null)
return NotFound();
product.Name = model.Name;
product.Description = model.Description;
product.Price = model.Price;
product.Category = model.Category;
await _productService.UpdateProductAsync(product);
return RedirectToAction(nameof(Index));
}
[HttpPost("delete/{id}")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Delete(int id)
{
await _productService.DeleteProductAsync(id);
return RedirectToAction(nameof(Index));
}
}
// Razor Pages example
public class ProductDetailsModel : PageModel
{
private readonly IProductService _productService;
public ProductDetailsModel(IProductService productService)
{
_productService = productService;
}
public Product Product { get; set; }
public async Task<IActionResult> OnGetAsync(int id)
{
Product = await _productService.GetProductByIdAsync(id);
if (Product == null)
return NotFound();
return Page();
}
public async Task<IActionResult> OnPostAddToCartAsync(int productId, int quantity)
{
var product = await _productService.GetProductByIdAsync(productId);
if (product == null)
return NotFound();
// Add to shopping cart logic
TempData["Message"] = $"{product.Name} added to cart!";
return RedirectToPage("/Cart/Index");
}
}
// View Models
public class ProductIndexViewModel
{
public List<Product> Products { get; set; }
public List<string> Categories { get; set; }
public string SelectedCategory { get; set; }
public int CurrentPage { get; set; }
public int TotalPages { get; set; }
}
public class ProductCreateModel
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[StringLength(500)]
public string Description { get; set; }
[Required]
[Range(0.01, 10000)]
public decimal Price { get; set; }
[Required]
public string Category { get; set; }
}
public class ProductEditModel
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Name { get; set; }
[StringLength(500)]
public string Description { get; set; }
[Required]
[Range(0.01, 10000)]
public decimal Price { get; set; }
[Required]
public string Category { get; set; }
}
// Entity Framework Context
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Name).IsRequired().HasMaxLength(100);
entity.Property(e => e.Price).HasColumnType("decimal(18,2)");
entity.HasIndex(e => e.Category);
});
}
}
// Service interface
public interface IProductService
{
Task<List<Product>> GetProductsAsync(string category = null, int page = 1, int pageSize = 10);
Task<Product> GetProductByIdAsync(int id);
Task<List<string>> GetCategoriesAsync();
Task CreateProductAsync(Product product);
Task UpdateProductAsync(Product product);
Task DeleteProductAsync(int id);
}
// Service implementation
public class ProductService : IProductService
{
private readonly AppDbContext _context;
public ProductService(AppDbContext context)
{
_context = context;
}
public async Task<List<Product>> GetProductsAsync(string category = null, int page = 1, int pageSize = 10)
{
var query = _context.Products.AsQueryable();
if (!string.IsNullOrEmpty(category))
{
query = query.Where(p => p.Category == category);
}
return await query
.OrderBy(p => p.Name)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
}
public async Task<Product> GetProductByIdAsync(int id)
{
return await _context.Products.FindAsync(id);
}
public async Task<List<string>> GetCategoriesAsync()
{
return await _context.Products
.Select(p => p.Category)
.Distinct()
.OrderBy(c => c)
.ToListAsync();
}
public async Task CreateProductAsync(Product product)
{
_context.Products.Add(product);
await _context.SaveChangesAsync();
}
public async Task UpdateProductAsync(Product product)
{
_context.Products.Update(product);
await _context.SaveChangesAsync();
}
public async Task DeleteProductAsync(int id)
{
var product = await _context.Products.FindAsync(id);
if (product != null)
{
_context.Products.Remove(product);
await _context.SaveChangesAsync();
}
}
}
// Models
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}8. Database & Entity Framework
Entity Framework Core
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace EFCoreExample
{
// DbContext - the main class that coordinates EF functionality
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
public DbSet<Author> Authors { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Configure relationships and constraints
modelBuilder.Entity<Blog>()
.HasMany(b => b.Posts)
.WithOne(p => p.Blog)
.HasForeignKey(p => p.BlogId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Post>()
.HasMany(p => p.Tags)
.WithMany(t => t.Posts)
.UsingEntity(j => j.ToTable("PostTags"));
modelBuilder.Entity<Author>()
.HasIndex(a => a.Email)
.IsUnique();
// Seed data
modelBuilder.Entity<Blog>().HasData(
new Blog { BlogId = 1, Url = "http://blogs.msdn.com/dotnet", Rating = 5 },
new Blog { BlogId = 2, Url = "http://blogs.msdn.com/visualstudio", Rating = 4 },
new Blog { BlogId = 3, Url = "http://blogs.msdn.com/webdev", Rating = 3 }
);
}
}
// Entity classes
public class Blog
{
public int BlogId { get; set; }
[Required]
[MaxLength(200)]
public string Url { get; set; }
public int Rating { get; set; }
// Navigation properties
public List<Post> Posts { get; set; } = new List<Post>();
public Author Author { get; set; }
public int? AuthorId { get; set; }
}
public class Post
{
public int PostId { get; set; }
[Required]
[MaxLength(200)]
public string Title { get; set; }
public string Content { get; set; }
public DateTime PublishedOn { get; set; }
public bool IsPublished { get; set; }
// Foreign key
public int BlogId { get; set; }
// Navigation properties
public Blog Blog { get; set; }
public List<Tag> Tags { get; set; } = new List<Tag>();
}
public class Tag
{
public int TagId { get; set; }
[Required]
[MaxLength(50)]
public string Name { get; set; }
// Navigation property (many-to-many)
public List<Post> Posts { get; set; } = new List<Post>();
}
public class Author
{
public int AuthorId { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
public string Bio { get; set; }
// Navigation property (one-to-one)
public Blog Blog { get; set; }
}
// Repository pattern with EF Core
public interface IBlogRepository
{
Task<Blog> GetBlogByIdAsync(int id);
Task<List<Blog>> GetAllBlogsAsync();
Task<List<Blog>> GetBlogsByRatingAsync(int minRating);
Task AddBlogAsync(Blog blog);
Task UpdateBlogAsync(Blog blog);
Task DeleteBlogAsync(int id);
Task<bool> SaveChangesAsync();
}
public class BlogRepository : IBlogRepository
{
private readonly BloggingContext _context;
public BlogRepository(BloggingContext context)
{
_context = context;
}
public async Task<Blog> GetBlogByIdAsync(int id)
{
return await _context.Blogs
.Include(b => b.Posts)
.Include(b => b.Author)
.FirstOrDefaultAsync(b => b.BlogId == id);
}
public async Task<List<Blog>> GetAllBlogsAsync()
{
return await _context.Blogs
.Include(b => b.Posts)
.Include(b => b.Author)
.OrderBy(b => b.Url)
.ToListAsync();
}
public async Task<List<Blog>> GetBlogsByRatingAsync(int minRating)
{
return await _context.Blogs
.Where(b => b.Rating >= minRating)
.Include(b => b.Posts)
.OrderByDescending(b => b.Rating)
.ToListAsync();
}
public async Task AddBlogAsync(Blog blog)
{
await _context.Blogs.AddAsync(blog);
}
public async Task UpdateBlogAsync(Blog blog)
{
_context.Blogs.Update(blog);
}
public async Task DeleteBlogAsync(int id)
{
var blog = await GetBlogByIdAsync(id);
if (blog != null)
{
_context.Blogs.Remove(blog);
}
}
public async Task<bool> SaveChangesAsync()
{
return await _context.SaveChangesAsync() > 0;
}
}
// Service layer
public class BlogService
{
private readonly IBlogRepository _blogRepository;
public BlogService(IBlogRepository blogRepository)
{
_blogRepository = blogRepository;
}
public async Task<List<Blog>> GetPopularBlogsAsync(int minRating = 4)
{
return await _blogRepository.GetBlogsByRatingAsync(minRating);
}
public async Task<Blog> CreateBlogAsync(string url, int rating, string authorName, string authorEmail)
{
var blog = new Blog
{
Url = url,
Rating = rating,
Author = new Author
{
Name = authorName,
Email = authorEmail
}
};
await _blogRepository.AddBlogAsync(blog);
await _blogRepository.SaveChangesAsync();
return blog;
}
public async Task<bool> UpdateBlogRatingAsync(int blogId, int newRating)
{
var blog = await _blogRepository.GetBlogByIdAsync(blogId);
if (blog == null)
return false;
blog.Rating = newRating;
await _blogRepository.UpdateBlogAsync(blog);
return await _blogRepository.SaveChangesAsync();
}
}
// Usage examples
class Program
{
static async Task Main(string[] args)
{
// Setup DI container in real applications
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True");
using var context = new BloggingContext(optionsBuilder.Options);
// Ensure database is created
await context.Database.EnsureCreatedAsync();
var repository = new BlogRepository(context);
var blogService = new BlogService(repository);
// CRUD operations
Console.WriteLine("=== EF CORE DEMONSTRATION ===\n");
// Create
var newBlog = await blogService.CreateBlogAsync(
"https://example.com/blog", 5, "John Doe", "john@example.com");
Console.WriteLine($"Created blog: {newBlog.Url}");
// Read
var blogs = await blogService.GetPopularBlogsAsync(4);
Console.WriteLine("\nPopular blogs:");
foreach (var blog in blogs)
{
Console.WriteLine($" - {blog.Url} (Rating: {blog.Rating})");
}
// Complex query with LINQ
var postsWithTags = await context.Posts
.Where(p => p.PublishedOn > DateTime.Now.AddMonths(-1))
.Include(p => p.Tags)
.Include(p => p.Blog)
.ThenInclude(b => b.Author)
.OrderByDescending(p => p.PublishedOn)
.ToListAsync();
Console.WriteLine("\nRecent posts with tags:");
foreach (var post in postsWithTags.Take(3))
{
Console.WriteLine($" - {post.Title} by {post.Blog.Author?.Name}");
Console.WriteLine($" Tags: {string.Join(", ", post.Tags.Select(t => t.Name))}");
}
// Raw SQL queries
var highRatedBlogs = await context.Blogs
.FromSqlRaw("SELECT * FROM Blogs WHERE Rating > {0}", 3)
.Include(b => b.Posts)
.ToListAsync();
// Transactions
using var transaction = await context.Database.BeginTransactionAsync();
try
{
// Multiple operations in transaction
context.Blogs.Add(new Blog { Url = "https://temp.com", Rating = 3 });
await context.SaveChangesAsync();
await transaction.CommitAsync();
}
catch
{
await transaction.RollbackAsync();
throw;
}
Console.WriteLine("\nEF Core operations completed!");
}
}
}Advanced EF Core and Performance
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System.Diagnostics;
namespace AdvancedEFCore
{
public class AdvancedBloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<Author> Authors { get; set; }
public DbSet<BlogStats> BlogStats { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
@"Server=(localdb)\mssqllocaldb;Database=AdvancedBlogging;Trusted_Connection=True")
.LogTo(Console.WriteLine, Microsoft.Extensions.Logging.LogLevel.Information)
.EnableSensitiveDataLogging();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Configure owned types (value objects)
modelBuilder.Entity<Author>().OwnsOne(a => a.Address);
// Configure table-valued functions
modelBuilder.HasDbFunction(typeof(AdvancedBloggingContext)
.GetMethod(nameof(GetPopularPosts), new[] { typeof(int) }))
.HasName("ufn_GetPopularPosts");
// Configure computed columns
modelBuilder.Entity<Post>()
.Property(p => p.Slug)
.HasComputedColumnSql("LOWER(REPLACE(Title, ' ', '-'))", stored: true);
// Configure concurrency tokens
modelBuilder.Entity<Blog>()
.Property(b => b.Version)
.IsRowVersion();
// Configure query filters
modelBuilder.Entity<Post>()
.HasQueryFilter(p => p.IsPublished);
}
// Table-valued function mapping
public IQueryable<Post> GetPopularPosts(int minLikes) =>
FromExpression(() => GetPopularPosts(minLikes));
}
// Entity with owned type
public class Author
{
public int AuthorId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public Address Address { get; set; }
public List<Blog> Blogs { get; set; } = new List<Blog>();
}
// Owned type (value object)
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
}
// Entity for keyless entity type (view/query)
[Keyless]
public class BlogStats
{
public int BlogId { get; set; }
public string BlogUrl { get; set; }
public int PostCount { get; set; }
public int TotalLikes { get; set; }
public DateTime LastPostDate { get; set; }
}
public class AdvancedBlogService
{
private readonly AdvancedBloggingContext _context;
public AdvancedBlogService(AdvancedBloggingContext context)
{
_context = context;
}
// Explicit loading
public async Task<Blog> LoadBlogWithPostsAsync(int blogId)
{
var blog = await _context.Blogs.FindAsync(blogId);
if (blog != null)
{
// Explicitly load related data
await _context.Entry(blog)
.Collection(b => b.Posts)
.Query()
.Where(p => p.IsPublished)
.LoadAsync();
await _context.Entry(blog)
.Reference(b => b.Author)
.LoadAsync();
}
return blog;
}
// Change tracking examples
public async Task DemonstrateChangeTracking()
{
var blog = await _context.Blogs.FirstAsync();
// Original values
var originalUrl = _context.Entry(blog).OriginalValues["Url"];
var currentUrl = _context.Entry(blog).CurrentValues["Url"];
Console.WriteLine($"Original URL: {originalUrl}");
Console.WriteLine($"Current URL: {currentUrl}");
Console.WriteLine($"State: {_context.Entry(blog).State}");
Console.WriteLine($"Modified: {_context.Entry(blog).Property(b => b.Url).IsModified}");
// Detect changes
_context.ChangeTracker.DetectChanges();
// Accept all changes
_context.ChangeTracker.AcceptAllChanges();
}
// Bulk operations with EF Core 7.0+
public async Task BulkUpdateBlogRatingsAsync(int oldRating, int newRating)
{
await _context.Blogs
.Where(b => b.Rating == oldRating)
.ExecuteUpdateAsync(setters => setters
.SetProperty(b => b.Rating, newRating)
.SetProperty(b => b.UpdatedAt, DateTime.UtcNow));
}
public async Task BulkDeleteOldPostsAsync(DateTime cutoffDate)
{
await _context.Posts
.Where(p => p.PublishedOn < cutoffDate && !p.IsPublished)
.ExecuteDeleteAsync();
}
// Complex query with multiple includes and filtering
public async Task<List<Blog>> GetBlogsWithRecentPostsAsync(int days = 30)
{
var cutoffDate = DateTime.UtcNow.AddDays(-days);
return await _context.Blogs
.Include(b => b.Author)
.Include(b => b.Posts
.Where(p => p.PublishedOn >= cutoffDate && p.IsPublished)
.OrderByDescending(p => p.PublishedOn)
.Take(5))
.ThenInclude(p => p.Tags)
.Where(b => b.Posts.Any(p => p.PublishedOn >= cutoffDate))
.OrderByDescending(b => b.Rating)
.AsSplitQuery() // Prevents Cartesian explosion
.ToListAsync();
}
// Raw SQL with parameters
public async Task<List<Blog>> SearchBlogsAsync(string searchTerm)
{
return await _context.Blogs
.FromSqlRaw(
"SELECT * FROM Blogs WHERE Url LIKE {0} OR BlogId IN (SELECT BlogId FROM Posts WHERE Title LIKE {1})",
$"%{searchTerm}%", $"%{searchTerm}%")
.Include(b => b.Posts)
.ToListAsync();
}
// Stored procedure execution
public async Task<int> UpdateBlogStatisticsAsync(int blogId)
{
var result = await _context.Database
.ExecuteSqlRawAsync("EXEC UpdateBlogStatistics @BlogId = {0}", blogId);
return result;
}
// Performance optimization: AsNoTracking
public async Task<List<Blog>> GetBlogsReadOnlyAsync()
{
return await _context.Blogs
.AsNoTracking() // No change tracking - better performance for read-only
.Include(b => b.Posts)
.AsNoTrackingWithIdentityResolution() // EF Core 5.0+
.ToListAsync();
}
// Global query filters
public async Task<List<Post>> GetAllPostsIncludingUnpublishedAsync()
{
return await _context.Posts
.IgnoreQueryFilters() // Bypass the IsPublished filter
.ToListAsync();
}
// Transaction with savepoints
public async Task ComplexOperationWithSavepointsAsync()
{
using var transaction = await _context.Database.BeginTransactionAsync();
try
{
// Operation 1
_context.Blogs.Add(new Blog { Url = "https://blog1.com", Rating = 4 });
await _context.SaveChangesAsync();
// Create savepoint
await transaction.CreateSavepointAsync("AfterBlog1");
// Operation 2 - might fail
try
{
_context.Blogs.Add(new Blog { Url = null, Rating = 5 }); // This will fail
await _context.SaveChangesAsync();
}
catch
{
// Rollback to savepoint
await transaction.RollbackToSavepointAsync("AfterBlog1");
}
// Operation 3 - continues after rollback
_context.Blogs.Add(new Blog { Url = "https://blog3.com", Rating = 3 });
await _context.SaveChangesAsync();
await transaction.CommitAsync();
}
catch
{
await transaction.RollbackAsync();
throw;
}
}
// Interceptors (EF Core 5.0+)
public void DemonstrateInterceptors()
{
// In real applications, you'd register these in DbContext configuration
// optionsBuilder.AddInterceptors(new MyCommandInterceptor(), new MyConnectionInterceptor());
}
}
// Performance benchmarking
public class EFPerformanceBenchmark
{
private readonly AdvancedBloggingContext _context;
public EFPerformanceBenchmark(AdvancedBloggingContext context)
{
_context = context;
}
public async Task MeasureQueryPerformanceAsync()
{
var stopwatch = Stopwatch.StartNew();
// Inefficient: N+1 query problem
var blogs = await _context.Blogs.ToListAsync();
foreach (var blog in blogs)
{
var posts = await _context.Posts
.Where(p => p.BlogId == blog.BlogId)
.ToListAsync(); // This causes N additional queries!
}
stopwatch.Stop();
Console.WriteLine($"N+1 queries: {stopwatch.ElapsedMilliseconds}ms");
stopwatch.Restart();
// Efficient: Single query with Include
var blogsWithPosts = await _context.Blogs
.Include(b => b.Posts)
.ToListAsync();
stopwatch.Stop();
Console.WriteLine($"Single query with Include: {stopwatch.ElapsedMilliseconds}ms");
stopwatch.Restart();
// More efficient: Filtered Include (EF Core 5.0+)
var blogsWithRecentPosts = await _context.Blogs
.Include(b => b.Posts.Where(p => p.IsPublished)
.OrderByDescending(p => p.PublishedOn)
.Take(5))
.ToListAsync();
stopwatch.Stop();
Console.WriteLine($"Filtered Include: {stopwatch.ElapsedMilliseconds}ms");
}
}
class Program
{
static async Task Main(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<AdvancedBloggingContext>();
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=AdvancedBlogging;Trusted_Connection=True");
using var context = new AdvancedBloggingContext(optionsBuilder.Options);
await context.Database.EnsureCreatedAsync();
var service = new AdvancedBlogService(context);
var benchmark = new EFPerformanceBenchmark(context);
Console.WriteLine("=== ADVANCED EF CORE FEATURES ===\n");
// Demonstrate complex queries
var blogs = await service.GetBlogsWithRecentPostsAsync(30);
Console.WriteLine($"Found {blogs.Count} blogs with recent posts\n");
// Demonstrate performance
await benchmark.MeasureQueryPerformanceAsync();
Console.WriteLine();
// Demonstrate change tracking
await service.DemonstrateChangeTracking();
Console.WriteLine();
// Demonstrate bulk operations
await service.BulkUpdateBlogRatingsAsync(3, 4);
Console.WriteLine("Bulk update completed\n");
Console.WriteLine("Advanced EF Core features demonstrated!");
}
}
}💻 Hands-On Practice Exercises
Beginner Level
- 1Create a console calculator that handles basic arithmetic operations
- 2Build a student grade management system with classes and objects
- 3Implement a simple bank account system with deposit/withdrawal functionality
- 4Create a temperature converter between Celsius and Fahrenheit
- 5Build a number guessing game with user input validation
Intermediate Level
- 1Develop a RESTful Web API for a todo list application
- 2Create a LINQ-based data analysis tool for sales data
- 3Build an ASP.NET Core MVC application for product catalog management
- 4Implement a file processing system with async/await operations
- 5Create a dependency injection container and demonstrate its usage
Advanced Level
- 1Build a full-stack e-commerce application with ASP.NET Core and Entity Framework
- 2Create a real-time chat application using SignalR
- 3Implement a microservices architecture with API Gateway pattern
- 4Build a machine learning model integration using ML.NET
- 5Create a high-performance data processing pipeline with parallel programming
🚀 Popular C# Frameworks & Technologies
ASP.NET Core
Cross-platform framework for building modern cloud-based web applications
- MVC Pattern
- Razor Pages
- Web API
- Dependency Injection
// Minimal API example
var app = WebApplication.Create(args);
app.MapGet("/", () => "Hello World!");
app.MapGet("/users/{id}", (int id) => $"User ID: {id}");
app.Run();Entity Framework Core
Modern object-database mapper for .NET with LINQ support
- Code First
- Migrations
- LINQ Queries
- Change Tracking
// EF Core DbContext
public class AppDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(
DbContextOptionsBuilder options)
=> options.UseSqlServer(connectionString);
}Blazor
Framework for building interactive web UIs using C# instead of JavaScript
- WebAssembly
- Server-side
- Components
- SignalR
// Blazor component
<button @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}Xamarin/.NET MAUI
Framework for building cross-platform mobile and desktop apps
- iOS & Android
- Windows & macOS
- Single Project
- Native UI
// MAUI ContentPage
<ContentPage>
<VerticalStackLayout>
<Label Text="Welcome to .NET MAUI!" />
<Button Text="Click me" Clicked="OnCounterClicked" />
</VerticalStackLayout>
</ContentPage>🎯 C# Career Paths
Backend Developer
ASP.NET Core, Web APIs, Microservices, Cloud
Full-Stack Developer
C# + JavaScript/TypeScript, Blazor, React/Angular
Game Developer
Unity Engine, Game Logic, Performance Optimization
Continue Your C# Journey!
You've now explored the comprehensive landscape of C# programming, from basic syntax to advanced enterprise development patterns. C# continues to evolve with each version, bringing modern features and performance improvements.
The .NET ecosystem offers endless possibilities - explore cloud development with Azure, build cross-platform apps with MAUI, create games with Unity, or dive into machine learning with ML.NET.