Practical C# examples covering OOP, async programming, generics, LINQ, and modern C# patterns — with real-world context for each concept.
This repository is a structured reference for C# language features and patterns, organised by concept. Each folder is a self-contained console project with runnable examples and inline comments that explain why a feature exists and when to reach for it in production code — not just what the syntax looks like.
Complements the production-quality QueueBacklogIntelligence project (Azure Service Bus monitoring · React · Docker) by demonstrating deep .NET/C# language knowledge.
| Folder | What it demonstrates | Real-world context |
|---|---|---|
| AsyncAwait/ | async/await, Task<T>, WhenAll, WhenAny, CancellationToken, ConfigureAwait |
Every I/O-bound API call, DB query, or file read in a production service |
| PatternMatching/ | is patterns, switch expressions, property/positional/relational patterns, list patterns (C# 8–11) |
Replacing long if/else if chains; discriminated unions; routing logic |
| RecordsAndValueTypes/ | record class, record struct, with expressions, readonly struct, struct vs class memory model |
Immutable DTOs, API response models, value objects (Money, Coordinate) |
| DelegatesAndEvents/ | Func, Action, Predicate, multicast delegates, event pattern, Expression<Func<T>> vs Func<T> |
LINQ providers, strategy pattern, pub/sub, EF Core query expressions |
| NullSafety/ | Nullable reference types, ?., ??, ??=, null-forgiving !, Nullable<T> |
Eliminating NullReferenceException; modern codebase migration to NRT |
| Abstraction/ | Abstract classes, abstract/virtual/sealed/override, template method | Domain model hierarchies; frameworks requiring extension points |
| Collections/ | List<T>, IEnumerable<T>, IReadOnlyList<T>, Dictionary, ConcurrentDictionary, word-frequency |
Choosing the right collection; thread-safe caching; batch processing |
| ControllerBasics/ | Default, parameterised, copy, private, static constructors; singleton pattern | DI container instantiation; one-time initialisation; factory patterns |
| Exception/ | Custom exception hierarchy, exception filters (when), correct re-throw, AggregateException |
Domain error handling; HTTP middleware; parallel error propagation |
| Generic/ | Result<T>, constrained generic methods (where T : IComparable<T>), generic repository |
Type-safe pipelines; reusable infrastructure without duplication |
| Interfaces/ | IRepository<T>, explicit interface implementation, default interface methods (C# 8) |
Dependency inversion; additive API evolution without breaking changes |
| Linq/ | Query syntax, method syntax, GroupBy, Join, Aggregate, paging, N-th highest salary |
Every data transformation in services, reports, and APIs |
| Polymorphism/ | Runtime dispatch (virtual/override), method hiding (new), method overloading |
Strategy pattern; plugin architecture; LSP demonstration |
| ReverseString/ | Four reversal approaches with complexity analysis; string.Create; Unicode grapheme-safe reversal |
Algorithm thinking; allocation-aware .NET string handling |
| Static/ | Static utility class, static constructor, sealed class, shared instance counter | BCL utility patterns (Math, Path); JIT optimisation; API hardening |
| Threading/ | Thread, ThreadPool, Task.Run, async/await I/O, lock for thread safety |
Background workers; CPU-bound parallelism; concurrent state management |
| ExtensionMethod/ | String extensions (ToTitleCase, Truncate), IEnumerable<T>.ToChunks, DistinctBy |
Extending sealed/third-party types; LINQ-style fluent APIs |
| ExtensionMethod/Delegate/ | Custom delegates, Func/Action/Predicate, lambda evolution, strategy via delegate |
Callback patterns; configurable behaviour injection |
| ExtensionMethod/DelegateEvent/ | Publisher/subscriber event pattern, typed EventArgs, null-safe ?.Invoke |
Domain event systems; UI event handling; audit log hooks |
Async I/O allows a single thread to handle thousands of concurrent operations. Without it, every database call, HTTP request, or file read blocks a thread pool thread — the bottleneck that kills throughput at scale. CancellationToken is the standard contract for graceful shutdown and request timeout.
Switch expressions with property patterns replace error-prone if/else if chains with exhaustive, readable dispatch logic. The compiler warns when a pattern arm is missing — catching bugs that silent fall-throughs would miss. Invaluable in routing, command handling, and domain rule engines.
record class makes DTOs and message objects immutable and value-comparable out of the box. with expressions enable the copy-with-modification pattern used in event sourcing and functional pipelines. readonly struct eliminates the GC pressure of small, frequently allocated objects.
Generic constraints (where T : IComparable<T>, where T : IEntity) let you write infrastructure once — a repository, a cache, a pipeline stage — that works for any domain type with zero code duplication. Unconstrained generics were the root cause of countless InvalidCastException bugs in pre-.NET 2.0 code.
LINQ moves transformation logic out of loops and into composable, readable pipelines. In combination with IQueryable<T>, LINQ expressions are translated into SQL by EF Core — meaning the same C# code both queries in-memory collections and generates optimal database queries.
Production-quality error handling distinguishes domain failures (ValidationException, NotFoundException) from infrastructure failures. Exception filters avoid the catch-and-rethrow anti-pattern that resets stack traces. AggregateException.Flatten() is essential for diagnosing failures in parallel/async operations.
Enabling <Nullable>enable</Nullable> turns NullReferenceException from a runtime surprise into a compile-time warning. Annotating APIs with string? vs string communicates intent and forces callers to handle the null case explicitly — the single most impactful change for reducing production crashes in a large codebase.
Delegates are the foundation of LINQ, event-driven architecture, and the strategy pattern. Understanding Expression<Func<T>> vs Func<T> is essential when working with ORMs — passing a compiled Func<T> to IQueryable.Where causes the entire table to load into memory, while an Expression<Func<T>> is translated to SQL.
Each folder is an independent console application. Open the solution in Visual Studio or run any project with:
# From a project folder, e.g.:
cd AsyncAwait
dotnet runOr open CSharpPatternsReference.sln in Visual Studio 2022, right-click any project, and select Set as Startup Project → Run.
| Language | C# 12 |
| Runtime | .NET 8 |
| IDE | Visual Studio 2022 |
Every project runs and produces readable console output. A few highlights:
AsyncAwait — Task.WhenAll parallel fan-out
=== Task.WhenAll — parallel fan-out ===
All regions completed in 401ms:
US: 300ms
EU: 200ms
APAC: 400ms
=== CancellationToken — cooperative cancellation ===
Processing batch 1/10...
Processing batch 2/10...
Processing batch 3/10...
Job was cancelled (token signalled).
PatternMatching — property patterns + switch expressions
=== Property Pattern ===
Order 1 (Alice): Process payment
Order 2 (Bob): Priority ship + notify VIP
Order 3 (Carol): Notify VIP
Order 4 (Dave): Skip
=== Relational + Logical Patterns ===
Score 45 → Fail
Score 65 → Pass
Score 85 → Merit
Score 95 → Distinction
DelegatesAndEvents — Expression<Func<T>> AST + event subscribers
=== Expression<Func<T>> vs Func<T> ===
Func filter: Gadget, Doohickey
Expression filter: Gadget, Doohickey
Expression body: (p.Price > 100)
=== Event Pattern (Publisher / Subscriber) ===
[OrderService] Processing order 101...
[Email] Confirmation sent to alice@example.com
[Inventory] Reserve stock for order 101
[Analytics] Log conversion event for order 101