Skip to content

About

400+ C# exercises on .NET 10 with xUnit tests: data structures, algorithms, LINQ, async, concurrency, design patterns, parsing, networking, ML basics, and more. Each one is small and runnable.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Repository files navigation

C# Exercises

Build & Test .NET C#

A collection of C# exercises covering language fundamentals, data structures, LINQ, object-oriented design and classic algorithms. Every exercise is covered by xUnit tests.

Exercises

Topic Exercise Concepts
Basics FizzBuzz tuple pattern matching, switch expressions
MathHelpers primes, factorial, Fibonacci (yield return), GCD
Strings StringExercises reverse, palindrome, anagram, run-length encoding, word frequency
LogParser [GeneratedRegex] with named groups, key=value extraction, redacting emails and card numbers
TemplateEngine {{ name | filter }} placeholders with Regex.Replace and a MatchEvaluator, fail-loud on missing values
UnicodeText grapheme-aware length, reverse and truncate, slugs via NormalizationForm.FormD, accent-insensitive compare
Collections Stack<T> generics, a growable array from scratch
BracketValidator using a stack to check nesting
LruCache<TKey, TValue> O(1) cache with a dictionary and a linked list
SinglyLinkedList<T> in-place reverse, fast/slow pointers, IEnumerable<T>
BinarySearchTree<T> insert, delete with in-order successor, iterative in-order traversal
MinHeap<T> array-backed heap, sift up/down, priority queue via IComparer<T>
Graph<T> adjacency list, BFS, DFS, shortest path, topological sort
Trie prefix tree for autocomplete, ranked suggestions, removal with pruning, iterative traversal
UnionFind<T> disjoint sets with union by size and path compression
RingBuffer<T> fixed-size circular buffer, overwrite-oldest, moving average, fail-fast enumeration
Deque<T> double-ended queue on a growable circular array, O(1) at both ends and by index
SkipList<T> sorted linked list with random "express lanes", O(log n) expected, range queries
LfuCache<TKey, TValue> O(1) least-frequently-used eviction with per-frequency lists, ties broken by recency
BiMap<TKey, TValue> lookups in both directions, keeping two dictionaries consistent
IntervalSet merged half-open ranges: adding merges, removing splits, finding free slots
AvlTree<T> self-balancing BST with rotations, subtree sizes for k-th smallest and rank
Rope a persistent tree of string pieces: cheap inserts and deletes, shared old versions
InsertionOrderedMap<TKey, TValue> a hash map plus linked list that keeps insertion order, or acts as an LRU cache
IndexedPriorityQueue<TItem, TPriority> a heap with a position index for decrease-key, Dijkstra without duplicate entries
Bag<T> a multiset with counts, most common items, multiset union, intersection and difference
LINQ LinqExercises GroupBy, MaxBy, CountBy, Chunk, records
MyLinq LINQ operators rebuilt with yield: deferred vs. immediate, streaming vs. buffering, eager argument checks
RangeSequence IEnumerable<T> / IEnumerator<T> written by hand: what the compiler generates for yield return
OOP Shapes abstraction, inheritance, polymorphism, primary constructors
BankAccount encapsulation, invariants, guard clauses
Design patterns Strategy swappable, composable discount rules for a shopping cart
Observer stock price alerts with IObservable<T> / IObserver<T>
Factory create shapes from text, register new ones without changing the factory
Decorator caching, logging and sale prices stacked around a price service
Builder fluent API producing an immutable, validated email
Command undo/redo history, commands that remember state, macros undone as one step
Chain of responsibility expense approvals passed along until someone decides
Visitor HTML, Markdown, word count and table of contents over a document tree via double dispatch
Composite files and folders behind one abstraction, sizes, search and a tree-style listing
Adapter wrapping a legacy Fahrenheit driver with error codes into an async Celsius interface
Proxy lazy (virtual) and protection proxies, a logging proxy generated with DispatchProxy
Template method fixed export steps with CSV and Markdown variants and optional hooks
Mediator a chat room routing broadcasts, direct messages and mutes
Memento opaque snapshots and named checkpoints with a capped history
State a connection whose behaviour changes by swapping state objects
Flyweight shared text styles: 11,000 characters, two style objects
Prototype shallow vs deep copies, a registry of templates
Null object a do-nothing audit log and a guest shopper instead of null checks
Bridge figures × drawing back-ends (SVG, canvas) varying independently
Dependency injection MiniContainer a DI container from scratch: reflection-based constructor injection, lifetimes, scopes, cycle and captive-dependency detection
Messaging Microsoft.Extensions.DependencyInjection: AddXxx extension, keyed services, TimeProvider, scope validation
Testing techniques RenewalService code designed for testing: dependencies as interfaces, TimeProvider for the clock
Test doubles hand-written dummy, stub, spy and fake, compared with NSubstitute mocks
SubscriptionBuilder test data builder with defaults and an implicit conversion
TimeBased rate limiter and debouncer tested instantly with FakeTimeProvider
SnapshotTesting approval tests with .received/.approved files and line diffs
FakeHttpHandler testing HttpClient code with canned responses, failure sequences and recorded requests
InMemoryFileSystem an IFileSystem fake with injectable failures
MutationTesting mutants made by rewriting expression trees, killed and surviving (and equivalent) mutants
Algorithms Sorting bubble sort, merge sort, quick sort (generic)
Searching binary search, Two Sum with a hash map
DynamicProgramming coin change (min coins & number of ways), longest common subsequence, edit distance
Dijkstra weighted shortest paths with a priority queue (reuses MinHeap<T>)
MinimumSpanningTree Kruskal's algorithm (reuses UnionFind<T>)
Backtracking permutations without duplicates, subsets, combination sum with pruning, N-Queens
Sudoku backtracking with bit-mask candidates and fewest-options-first
StringSearch Knuth–Morris–Pratt substring search in O(n + m)
Knapsack 0/1 knapsack with item reconstruction, a one-row version, why greedy fails, subset sum
LongestIncreasingSubsequence patience sorting in O(n log n), nesting envelopes
MaximumSubarray Kadane's algorithm, circular arrays, best single trade
WordBreak splitting unspaced text into words: memoised search, all splits, fewest words
MatrixChain interval DP for the cheapest multiplication order
IntervalScheduling greedy by end time, room assignment with a priority queue, weighted scheduling with DP
EggDrop the "floors covered by d drops" reformulation vs. the direct DP, a two-egg plan
PalindromeDp longest palindromic subsequence, minimum insertions and palindrome partitions
PatternMatchingDp regex ./* and SQL LIKE matching as DP tables
RodCutting the textbook DP, with cutting costs
GridPaths counting paths around obstacles, cheapest path reconstruction
StockTrading buy/sell state machines: unlimited, k trades, cooldown, fees, checked by brute force
Caching TtlCache<TKey, TValue> absolute and sliding expiration on TimeProvider, lazy expiry, compaction, hit/miss counts
SingleFlight<TKey, TValue> stampede protection: concurrent requests for a key share one load, per-caller cancellation
CachedLookup<TKey, TValue> cache-aside with negative caching and invalidation
Immutable data PersistentStack<T> / PersistentQueue<T> structural sharing, O(1) versions, a queue from two stacks
UndoableEditor undo/redo with snapshots of an ImmutableList<T> document, bounded history
ReadOnlyExposure IReadOnlyList vs ReadOnlyCollection vs ImmutableArray, FrozenDictionary
I/O & binary data ReadingsFile a versioned binary format: magic number, BinaryWriter/BinaryReader, CRC-32 trailer, reading old versions, distrusting counts
Crc32 table-driven checksum, computed incrementally
PacketHeader big-endian network headers with BinaryPrimitives on spans, validating untrusted input
CountingStream a Stream decorator, measuring gzip size without buffering, constant-memory CSV processing
Numerics FloatingPoint why 0.1 + 0.2 != 0.3, tolerant comparison, Kahan summation, ULP distance
Rational exact fractions on BigInteger with operator interfaces, a valid default
NumberTheory modular exponentiation with UInt128, modular inverse, deterministic Miller–Rabin, fast-doubling Fibonacci
Fixed16 Q16.16 fixed-point arithmetic, integer-only square root
ContinuedFractions convergents, best rational approximations (355/113), repeating decimals as fractions
BaseConversion any base with BigInteger, negabinary, balanced ternary, spreadsheet column names
Interval interval arithmetic for tolerances, the dependency problem
Divisors divisor counts and sieves, perfect and amicable numbers
Hashing StableHash why string.GetHashCode() is randomised, FNV-1a, a SplitMix64 finalizer
OpenAddressingMap<TKey, TValue> a hash map from scratch: linear probing, tombstones, power-of-two sizing, load factor
BloomFilter probabilistic set membership, sizing formulas, double hashing
ConsistentHashRing<TNode> sharding with virtual nodes: adding a server moves ~1/n of the keys instead of most of them
Modern C# Records immutable order with with expressions, value equality over collections
ListPatterns [first, .., last], slice patterns, a text command parser
GenericMath INumber<T>, IBinaryInteger<T>, a custom Vector2D<T> with operator interfaces
SpanExercises allocation-free parsing, string.Create, in-place rotation with Span<T>
Async ParallelDownloader Task.WhenAll, throttling with SemaphoreSlim, racing with Task.WhenAny
Resilience retry with exponential backoff, timeouts via CancellationToken
AsyncStreams IAsyncEnumerable, [EnumeratorCancellation], producer/consumer with Channel<T>
AsyncCoordination AsyncLock across awaits, AsyncManualResetEvent with RunContinuationsAsynchronously, AsyncLazy<T> with retry
AsyncBatcher<T> flushing by size or age on a channel, per-item completion
KeyedLock<TKey> one async lock per key with reference-counted cleanup
PeriodicJob PeriodicTimer on a TimeProvider, no overlapping runs, surviving failures
CallbackAdapters callbacks, events and timers wrapped as tasks with TaskCompletionSource
ProgressReporting IProgress<T> with a throttle that always delivers the final report
Concurrency Counters lost updates from ++, lock with System.Threading.Lock, Interlocked, a lock-free max with compare-and-swap
BoundedBuffer<T> blocking producer/consumer queue with Monitor.Wait / PulseAll
OnceCache<TKey, TValue> ConcurrentDictionary + Lazy<T> so the factory runs once per key, retry after a failed build
LockFreeStack<T> Treiber stack with compare-and-swap, SpinWait back-off, why .NET has no ABA problem here
ReadWriteCache<TKey, TValue> ReaderWriterLockSlim with an upgradeable lock so a missing value is built once
Actor lock-free state owned by one mailbox loop on a Channel<T>, post and ask
ParallelAggregation thread-local partial sums vs. a shared lock, parallel histograms, PLINQ
PhasedComputation Barrier phases with double buffering, CountdownEvent, exceptions on pool threads
StripedMap<TKey, TValue> lock striping, consistent counts by taking locks in a fixed order
Domain modelling PrefixedIds strongly typed cus_… / ord_… ids with static abstract members, time-ordered Guid.CreateVersion7
ValueObjects always-valid EmailAddress via Result<T>, DateRange with overlap, intersection and merging
Allocation splitting money without losing cents: largest-remainder method, by ratios, refunds
Specification<T> composable business rules as expression trees (&, |, !), parameter rebinding, usable with IQueryable
Error handling Result<T> errors as values: Map, Bind, Ensure, Match, LINQ query syntax, combining independent results
SignupValidator form validation that fails fast vs. reports every error, cross-field rules
ExceptionHandling every failure from Task.WhenAll, cleanup steps that all run, ExceptionDispatchInfo to keep stack traces
Reflection PropertyAccessor expression trees compiled into fast getters and setters instead of PropertyInfo.GetValue
AttributeValidator custom attributes ([Required], [Range], [MaxLength]) read once per type and cached
CommandRegistry plugin discovery: scan assemblies for [Command] classes, create them with Activator
ObjectDumper printing any object graph with cycle detection and a depth limit
DeepCloner deep copies of fields (private ones too), shared references and cycles preserved
ObjectDiff property-level changes with paths like Address.City, for audit logs
ObjectMapper an AutoMapper-style mapper compiled from expression trees, with unmapped-member checks
Serialization Money custom JsonConverter<T> writing a value object as "12.50 EUR", errors with the JSON path
OrderEvents polymorphic JSON with [JsonDerivedType], source-generated JsonSerializerContext, strict unknown-member handling, event replay
Resource management Disposables idempotent Dispose, ObjectDisposedException, disposing in reverse order, IAsyncDisposable with await using
Pooling an object pool with allocation-free struct leases, renting buffers from ArrayPool<T>.Shared
Delegates & events Functional composing functions, currying, partial application, memoizing recursive functions
TemperatureSensor the standard event pattern, isolating handlers that throw, unsubscribing lambdas with an IDisposable token
MiddlewarePipeline ASP.NET Core-style middleware built by composing next => handler delegates, short-circuiting
State machines StateMachine<TState, TTrigger> table-driven transitions with a fluent API, guards with reasons, entry/exit actions, history
DocumentWorkflow draft → review → approved → published, approval quorum, rules that read like requirements
VendingMachine a pure (state, event) => (state, effects) function with pattern matching, replayable and immutable
Dates & times CalendarMath DateOnly, age with 29 February birthdays, nth weekday of a month, Easter, business days with holidays
TimeZones skipped and repeated local times around DST, "same time tomorrow", shared working hours, a weekly schedule
RecurrenceRule iCalendar RRULEs (daily, weekly by day, monthly), COUNT and UNTIL, skipping short months
BusinessHours SLA due dates in working time, skipping nights, weekends and holidays
RelativeTime "5 minutes ago", "yesterday", "in 3 weeks", compact "3h" forms
Iso8601 ISO week numbers around New Year, P1DT2H durations with calendar-aware adding
Parsing Lexer turning text into tokens, syntax errors with positions
Parser recursive descent: precedence and associativity from the grammar, a syntax tree of records
ExpressionTools evaluating with variables and functions, constant folding, printing with minimal parentheses
Generics NotificationBus contravariant handlers (in T), dispatch on the runtime type, covariance and the array covariance trap
EnumInfo<TEnum> a static generic class as a per-type cache, struct, Enum constraint, IParsable<T> with static abstract members
Compression & encoding Varint LEB128 variable-length integers, ZigZag for negatives, delta-encoding sorted timestamps, overflow-safe decoding
Huffman optimal prefix codes with PriorityQueue, canonical codes so the header stores only lengths, bit-level reading and writing
Base32 Crockford's alphabet for codes humans type, forgiving decoding, a mod-37 check symbol that catches typos and swaps
Lz77 sliding-window back-references with hashed match search, overlapping copies
Lzw a dictionary built on the fly by both sides, the "cScSc" special case
BurrowsWheeler the bzip2 transform that groups similar characters, and its inverse
MoveToFront turning runs into zeros, measured with Shannon entropy
BitPacking storing values in exactly the bits they need, frame-of-reference for timestamps
Diffing MyersDiff the shortest edit script in O((N+M)·D), the algorithm behind git diff, walking the path back through saved frontiers
UnifiedDiff diff -u output: hunks with context, merging nearby changes, @@ -l,s +l,s @@ headers, parsing a diff back
Patch applying hunks to a file that changed since the diff was made: nearest-match search, offsets, conflicts
Geometry Vec / Segments dot and cross products, orientation, segment intersection without division, point-to-segment distance
ConvexHull Andrew's monotone chain in O(n log n), diameter
Polygon shoelace area, winding order, centroid, ray-casting containment, convexity
ClosestPair divide and conquer with a strip check, verified against brute force
GeoDistance haversine distance, initial bearing, bounding boxes for "within r km"
RectangleUnion area of overlapping rectangles with a sweep line
Bit manipulation BitTricks power-of-two tests, Kernighan popcount, lowest set bit, bit reversal, Gosper's hack, subset enumeration
BitSet 64 flags per ulong, set operations, enumerating with trailing-zero counts, a bit-packed sieve
GrayCode sequences where neighbours differ by one bit, encoding and decoding
MortonCode Z-order curves by interleaving bits, a cheap spatial index
TravellingSalesman Held–Karp dynamic programming over bit-mask subsets
Range queries PrefixSums O(1) range sums in 1D and 2D, counting subarrays with a given sum
FenwickTree binary indexed tree with O(n) build, counting inversions
SegmentTree<T> bottom-up, iterative, any associative operation, order-preserving for non-commutative ones
SparseTable O(1) range minimum on static data with overlapping power-of-two windows
DifferenceArray batched range updates, peak overlap of bookings
SlidingWindow window maximums with a monotonic deque, longest substring without repeats, shortest window with a sum
Graph algorithms StronglyConnectedComponents Tarjan's algorithm in one DFS, condensation
BellmanFord negative weights, finding the negative cycle, currency arbitrage with -log(rate)
FloydWarshall all-pairs shortest paths, next-hop path reconstruction, graph centre
Bipartite two-colouring with BFS, maximum matching with augmenting paths
MaxFlow Edmonds–Karp with residual capacities, the minimum cut
GridPathfinding A* with a Manhattan heuristic and weighted cells, compared with Dijkstra
CriticalConnections bridges and articulation points with low-link values
EulerianPath Hierholzer's algorithm, reconstructing an itinerary from tickets
PrimMst minimum spanning trees grown from a vertex with a priority queue
GraphColoring greedy and Welsh–Powell colouring, exact chromatic numbers by backtracking
TransitiveClosure Warshall's algorithm on BitArray rows, transitive reduction
LowestCommonAncestor binary lifting for O(log n) ancestor queries and tree distances
TreeMetrics tree diameter with two searches, the tree centre
Text algorithms RabinKarp rolling hashes mod a Mersenne prime, longest repeated substring by binary search
ZFunction prefix-match lengths in O(n), pattern search, smallest period
Manacher longest palindromic substring in O(n)
SuffixArray prefix doubling, Kasai's LCP array, substring search, distinct substrings
AhoCorasick many patterns in one pass with failure links, a word censor
Soundex phonetic codes so "Robert" matches "Rupert"
WordWrap greedy line breaking vs. minimum raggedness with DP
Randomness Xoshiro256 a seeded PRNG, SplitMix64 seeding, unbiased bounded integers with Lemire's method
Shuffling Fisher–Yates vs. the biased naive shuffle, sampling without replacement
ReservoirSampler<T> uniform samples from a stream of unknown length, weighted reservoir sampling
AliasTable<T> Vose's alias method: O(1) weighted draws
MonteCarlo estimating π, the birthday paradox, Monty Hall
Statistics RunningStats Welford's one-pass variance, merging partial results, why E[x²] - E[x]² fails
StreamingMedian median of a stream with two heaps
Percentiles nearest-rank vs. interpolated percentiles, quickselect
HyperLogLog counting distinct items in 4 KB, merging sketches
CountMinSketch approximate counts that never underestimate, heavy hitters
LinearRegression least squares fit, R², correlation
MovingAverages simple and exponential moving averages, half-life decay for irregular samples
Linear algebra Matrix immutable row-major matrix, cache-friendly multiplication order
GaussianElimination solving systems with partial pivoting, determinant, Gauss–Jordan inverse
MatrixPower exponentiation by squaring for Fibonacci, Tribonacci and counting walks
GridTransforms in-place rotation, spiral order, searching a sorted matrix
Transform2D affine transforms in homogeneous coordinates, composition, inverse, rotating around a point
PageRank power iteration with damping and dead ends
Reliability TokenBucket burst-friendly rate limiting with lazy refill on TimeProvider, Retry-After
CircuitBreaker closed → open → half-open with a single trial call, state change events
Bulkhead capping concurrency plus a queue, rejecting the rest immediately
LoadBalancer smooth weighted round-robin, health checks, power of two choices
TimingWheel O(1) timeouts in hashed slots with rotation counts
CronSchedule five-field cron parsing with lists, ranges and steps, the day-of-month/day-of-week rule
Codecs Base64Codec 6-bit groups and padding by hand, URL-safe variant, strict decoding
HexDump hex with nibble arithmetic, an xxd-style dump
PercentEncoding RFC 3986 escaping of UTF-8 bytes, + for spaces in forms, query strings
Utf8Codec UTF-8 by hand, rejecting overlong forms and surrogates, truncating on character boundaries
RomanNumerals greedy encoding, parsing that rejects non-canonical numerals
NumberToWords spelling numbers in English, cheque amounts, ordinals
File formats Csv RFC 4180 state machine: quotes, escaped quotes, embedded newlines, headers
IniFile sections, comments, quoted values, ${section.key} references, typed reads with IParsable<T>
MiniJson a complete JSON parser and serializer with positioned errors and a nesting limit
SemanticVersion semver precedence (pre-releases, numeric identifiers), caret ranges
CommandLine --name value, --name=value, bundled flags, --, shell-style splitting
HumanReadable 1.5 GiB vs 1.5 GB, 2h30m durations, both directions
FixedWidth column-based records, padding rules, implied decimals with trailing signs
Logfmt key=value log lines with quoting, escaping and bare flags
NdJson streaming JSON Lines with IAsyncEnumerable, skipping and reporting bad lines
RssFeed RSS and Atom with LINQ to XML, reading either format
Simulations GameOfLife Conway's Life on an unbounded board stored as a set of live cells
ElementaryAutomaton Wolfram rules 30, 90 and 110
TicTacToe negamax with alpha-beta pruning, perfect play ends in a draw
Maze recursive backtracker with an explicit stack, BFS solving, ASCII rendering
FloodFill iterative paint bucket, counting islands, capturing surrounded regions
QueueSimulation discrete-event simulation of tellers, compared with M/M/1 queueing theory
Boids flocking from separation, alignment and cohesion on a wrapping world
EloRating rating updates by surprise, convergence to true strength
DiceProbability exact distributions by convolution, "roll 4, keep 3", advantage
SirModel epidemics, R₀, the peak and herd immunity
PredatorPrey Lotka–Volterra cycles with RK4 and a conserved quantity
GamblersRuin random walks with absorbing barriers, the cost of a house edge
Functional programming Option<T> an optional value instead of null, Map/Bind/Match, LINQ query syntax
Trampoline deep and mutual recursion in constant stack space
Lens composable getters and immutable setters for nested records
Zipper<T> an immutable list with an O(1) cursor
Monoids IMonoid<T> with static abstract members, parallel folds, Kadane as a monoid
ParserCombinators small parsers combined with Or, Many and LINQ into a calculator grammar
Checksums Luhn payment card check digits, card brands, the 09 ↔ 90 blind spot
Iban mod 97 by long division, country lengths, helpful error messages
Isbn ISBN-10 (mod 11) and ISBN-13 (EAN), converting between them
Damm a quasigroup table that catches every single error and adjacent swap
Finance Amortization annuity payments, a cent-exact repayment schedule, the effect of paying extra
CashFlows NPV, IRR with Newton's method and a bisection fallback, payback period, compounding
Combinatorics Binomial exact binomials without factorials, Pascal's triangle, Lucas' theorem mod a prime
Permutations next permutation in place, rank and unrank via factorial base, derangements
Combinations lazy k-combinations, cartesian products as an odometer, listing change-making ways
Partitions integer partitions, Stirling numbers of the second kind, Bell numbers
Catalan balanced brackets and binary tree shapes
InclusionExclusion counting divisible numbers over bit-mask subsets, surjections, Euler's totient
Fuzzy matching JaroWinkler name similarity with transpositions and a prefix bonus
DamerauLevenshtein edit distance counting swaps, a banded version with early exit
NGramSimilarity Jaccard and Dice over n-grams, a trigram index
BkTree fuzzy dictionary lookup pruned by the triangle inequality
SpellChecker Norvig's corrector: candidate edits ranked by word frequency
MinHash estimating Jaccard similarity of documents from small signatures
Search engine Tokenizer lower-casing, accent folding, stop words, a light stemmer, positions
InvertedIndex posting lists, merge intersection, NOT, phrase queries with positions
Ranking TF-IDF and BM25 with term saturation and length normalisation
QueryParser a AND (b OR "c d") -e parsed into a tree and evaluated
Snippets best matching window with highlighted terms
Autocomplete prefix ranges by binary search, top-k by popularity
Operating systems CpuScheduling FCFS, shortest job first, round-robin, Gantt charts and waiting times
PageReplacement FIFO, LRU, optimal and clock, Belady's anomaly
BankersAlgorithm deadlock avoidance with safe sequences
DiskScheduling FCFS, shortest seek, SCAN (elevator), C-SCAN
FreeListAllocator first, best and worst fit, splitting, coalescing, fragmentation
BuddyAllocator power-of-two blocks, buddies found by flipping one bit
Networking Ipv4Network CIDR parsing, membership, subnetting, summarising a range into blocks
RoutingTable longest prefix match in a binary trie
InternetChecksum RFC 1071 ones'-complement checksum, incremental updates, an IPv4 header
HttpMessageParser incremental HTTP/1.1 parsing, chunked bodies, limits, smuggling checks
Backoff exponential backoff with full, equal and decorrelated jitter, measured spikes
UriTemplate RFC 6570 expansion with operators and escaping
Distributed systems LamportClock logical timestamps and a causally consistent total order
VectorClock detecting concurrent writes, keeping siblings in a replica
Crdts G-counter, PN-counter, LWW register, observed-remove set
MerkleTree finding differing blocks in O(log n) comparisons, inclusion proofs
SnowflakeId time-sorted 64-bit ids without coordination, clock-skew protection
TwoPhaseCommit prepare and vote, commit or abort everyone, timeouts as no votes
Event sourcing EventStore append-only streams, optimistic concurrency, global positions
InventoryItem an aggregate rebuilt from events, decisions separate from state changes
Projections read models that catch up idempotently, a daily report
Snapshots loading from a snapshot plus the events after it
Saga multi-step transactions with compensation in reverse order
Upcasting converting old event versions step by step when reading
Spatial indexes QuadTree<T> adaptive subdivision, range and radius queries
KdTree<T> nearest and k-nearest neighbours with pruning
GeoHash interleaved lat/long bits as base-32 strings, neighbouring cells
SpatialHashGrid collision broad phase in near-linear time
IntervalTree<T> overlap queries with subtree max-end pruning
Image processing Colors hex, RGB ↔ HSL, mixing, WCAG contrast ratio and readable text colour
Convolution blur, sharpen, Sobel edges, a summed-area-table box blur
Dithering threshold vs Floyd–Steinberg vs ordered (Bayer) dithering
Histogram equalisation, contrast stretch, Otsu's threshold
Resampling nearest neighbour and bilinear resizing, fitting thumbnails
Netpbm reading and writing PGM images (ASCII and binary)
Signal processing Fourier DFT vs Cooley–Tukey FFT, dominant frequencies, polynomial multiplication
Dtmf generating and decoding phone tones with the Goertzel algorithm
WavFile writing and reading RIFF/WAVE PCM, skipping unknown chunks
Filters one-pole low-pass and high-pass, median filter for spikes
PitchDetection autocorrelation pitch detection, nearest note and cents
Interpreters ShuntingYard infix to RPN with associativity, unary minus and functions
StackMachine a bytecode VM with calls and jumps, a two-pass assembler
TinyRegex Thompson NFA matching without catastrophic backtracking
TinyLisp reader, eval, closures, let, and tail calls in a loop
Brainfuck bracket pre-pairing and run folding
Numerical methods RootFinding bisection, Newton and secant, convergence speed compared
Integration trapezoid, Simpson, adaptive Simpson, Monte Carlo
Interpolation linear, Lagrange (and Runge's phenomenon), natural cubic splines
GradientDescent numerical gradients, momentum, fitting a line, the Rosenbrock valley
OdeSolvers Euler, RK4, semi-implicit Euler conserving a spring's energy
SimulatedAnnealing 2-opt moves with a cooling schedule on a 100-city tour
Security PasswordHasher salted PBKDF2, constant-time comparison, rehashing on cost upgrades
SignedToken HS256 JWTs by hand, rejecting alg: none, tampering and expiry
Totp RFC 6238 codes, drift window, replay protection, provisioning URIs
PasswordStrength entropy estimates discounted for common words, repeats and sequences
HtmlSanitizer allowlisted tags and attributes, safe URL schemes
Commerce VatCalculator rounding per line vs per rate, extracting VAT from gross prices
TieredPricing volume vs graduated tiers, price cliffs
Proration plan changes mid-cycle by actual days, partial first periods
InventoryReservations holding stock with expiry, confirming and releasing
CurrencyConverter triangulated rates, minor units per currency, spreads
Data processing Joins nested loop, hash and merge joins, left outer joins
ExternalSort sorted runs on disk merged with a lazy, stable k-way merge
PivotTable<TRow> rows × columns aggregation with totals and a text rendering
TimeSeries resampling into buckets, zero / forward / interpolated gap filling, counter resets
WindowFunctions ROW_NUMBER, RANK, DENSE_RANK, LAG, running totals, moving averages
SnapshotDiff added, removed and modified records between two exports, field by field
Property-based testing Gen<T> composable random generators with shrinkers
Property checking properties over generated inputs, shrinking counterexamples, replayable seeds
Text formatting CaseConverter camel, Pascal, snake, kebab and title case, acronyms like HTTPResponse
NaturalComparer "file2" before "file10", digit runs of any length
Glob *, **, ? and [a-z] path matching without exponential backtracking
TextTable aligned console tables, numbers right-aligned, truncation
Pluralizer English plural rules and exceptions, "1 file" / "2 files"
MiniMarkdown a safe Markdown subset to HTML: escaping first, protected code spans
Puzzles TowerOfHanoi recursive and iterative solutions, a move validator
WordLadder BFS over words bucketed by wildcard patterns
KnightsTour Warnsdorff's heuristic with a little backtracking
SlidingPuzzle the 8-puzzle solved optimally with A*, solvability by inversion parity
WaterJugs state-space BFS, possibility by gcd
Josephus simulation, the O(n) recurrence, the bit-rotation closed form
Ciphers Caesar shifting letters, cracked with chi-squared letter frequencies
Vigenere key length from the index of coincidence, then per-column Caesar attacks
ToyRsa RSA from the maths up (and why textbook RSA is insecure)
DiffieHellman key agreement over a safe prime, HKDF, the real thing with ECDH
SecretSharing Shamir's k-of-n sharing over a prime field
AuthenticatedEncryption AES-GCM done right: fresh nonces, associated data, tamper detection
Machine learning KMeans clustering with k-means++ initialisation, the inertia elbow
NearestNeighbors<TLabel> k-NN classification with feature standardisation
NaiveBayes a spam filter with log probabilities and Laplace smoothing
LogisticRegression gradient descent on cross-entropy, precision and recall
DecisionTree Gini splits, depth limits, rules you can read
Perceptron why XOR needs a hidden layer, and a tiny backpropagation network that learns it
Web RouteMatcher route templates with constraints, optional and catch-all parameters, most-specific-wins, link generation
ContentNegotiation Accept and Accept-Language with q-values and specificity
ConditionalRequests ETags: 304 Not Modified, 412 for lost updates, 428 to require them
Pagination cursor vs offset paging under inserts, opaque cursors, Link headers
CorsPolicy origins, preflights, credentials and Vary
Cookies Cookie and Set-Cookie parsing, secure defaults, Max-Age vs Expires
UrlShortener base-62 codes from a scrambled counter, aliases, click counts
Accounting Ledger double-entry bookkeeping, trial balance, the accounting equation
Depreciation straight-line, declining balance (with the switch), sum of the years' digits
InventoryCosting FIFO, LIFO and weighted average cost of goods sold
Reconciliation matching bank lines to the books by reference, then by amount and date
AgingReport receivables by days overdue, bad debt allowance, DSO
Planning CriticalPath earliest and latest starts, slack, the critical chain
BinPacking next fit, first fit (decreasing), exact branch and bound
ConstraintSolver backtracking with MRV and forward checking: map colouring, exam timetables
Assignment the Hungarian algorithm in O(n³), checked against brute force
Recommendations CollaborativeFiltering user similarity on mean-centred ratings, predicted ratings
AssociationRules Apriori frequent itemsets, rules with confidence and lift
RankingFormulas Hacker News gravity, Reddit hot, Wilson lower bound, Bayesian averages
Diagnostics StructuredLogger message templates with named properties, scopes on AsyncLocal
Metrics counters, gauges, bucketed histograms with percentile estimates, Prometheus output
Tracing span trees across awaits, traceparent propagation
HealthChecks parallel checks with timeouts, critical vs degraded
CorrelationContext how AsyncLocal flows down but not back up, suppressing flow
LogDeduplicator "last message repeated N times" instead of log floods

Project structure

csharp-exercises/
├── src/CSharpExercises/                    # exercise implementations, one folder per topic
├── src/CSharpExercises.Api/                # ASP.NET Core minimal API built on the exercises
├── tests/CSharpExercises.Tests/            # xUnit unit and integration tests
└── benchmarks/CSharpExercises.Benchmarks/  # BenchmarkDotNet performance comparisons

Getting started

Requires the .NET 10 SDK.

git clone https://github.com/dejanciev-dev/csharp-exercises.git
cd csharp-exercises
dotnet test

Web API

CSharpExercises.Api puts the exercises together in an ASP.NET Core minimal API:

Endpoint Uses
POST /api/sort bubble / merge / quick sort
POST /api/routes/shortest Dijkstra (with the hand-written MinHeap<T>)
GET /api/coins dynamic programming coin change
GET /api/text/edit-distance, /lcs, /palindrome dynamic programming and string exercises
GET / POST /api/shapes shape factory (injected via DI)

Along the way it shows input validation with ProblemDetails responses, limits that stop expensive algorithms from being abused (bubble sort is capped at 5,000 numbers), rate limiting with the SlidingWindowRateLimiter from the testing exercises (429 + Retry-After), options bound from appsettings.json, and an OpenAPI document.

dotnet run --project src/CSharpExercises.Api
curl -X POST http://localhost:5028/api/sort -H "Content-Type: application/json" \
     -d '{"algorithm":"quick","numbers":[5,2,9,1]}'
# {"algorithm":"quick","count":4,"sorted":[1,2,5,9]}

More sample requests are in CSharpExercises.Api.http, and the OpenAPI document is at /openapi/v1.json in Development. Integration tests run the whole app in memory with WebApplicationFactory, swapping in a fake clock to test rate limiting without waiting.

Benchmarks

The benchmarks project uses BenchmarkDotNet to compare the hand-written sorts against Array.Sort and LINQ, and the Span<T> CSV parser against string.Split.

# quick run (a few minutes); drop --job short for full statistical precision
dotnet run -c Release --project benchmarks/CSharpExercises.Benchmarks -- --filter '*' --job short

# just one class
dotnet run -c Release --project benchmarks/CSharpExercises.Benchmarks -- --filter '*Csv*'

Sorting 10,000 integers

Method Random Already sorted Reversed Allocated
Array.Sort (baseline) 0.67 ms 0.07 ms 0.18 ms 39 KB
LINQ Order() 0.64 ms 0.08 ms 0.18 ms 39 KB
QuickSort 0.94 ms 0.15 ms 0.16 ms 39 KB
MergeSort 2.32 ms 1.18 ms 1.56 ms 2,133 KB
BubbleSort 145.9 ms 0.01 ms 93.8 ms 39 KB

What the numbers show:

  • Big-O wins at scale. Bubble sort is O(n²): about 200× slower than Array.Sort on 10,000 random items, but only 10× slower on 100.
  • Best cases matter. Bubble sort stops after one pass when nothing swaps, so on already-sorted input it is the fastest of all.
  • Allocations cost time. Merge sort creates new arrays at every level of recursion (2 MB vs 39 KB), which is the main reason it trails quick sort.
  • Benchmarking finds bugs. The first version of QuickSort always picked the last element as pivot. On sorted input that is its worst case, and it crashed with a stack overflow at 10,000 items. It now uses a middle pivot with Hoare partitioning and recurses only into the smaller half.

Summing a CSV line

Method 10 fields 1,000 fields Allocated (1,000 fields)
string.Split + int.Parse 438 ns 61.4 µs 70 KB
SumCsv with ReadOnlySpan<char> 239 ns 33.4 µs 0 B

Slicing spans instead of creating substrings makes parsing about 45% faster and allocation-free.

Measured with BenchmarkDotNet 0.15.8 --job short on .NET 10, Intel Core i7-6700HQ, Windows 10. Short runs are indicative; absolute numbers will differ on your machine.

Roadmap

Ideas for upcoming exercises:

  • Async: parallel downloads with Task.WhenAll, cancellation tokens, IAsyncEnumerable
  • Data structures: linked list, binary search tree, min-heap / priority queue, graph with BFS & DFS
  • Algorithms: dynamic programming (coin change, longest common subsequence), Dijkstra
  • Design patterns: strategy, observer, factory, decorator, builder
  • Modern C#: records with with expressions, list patterns, generic math (INumber<T>), Span<T>
  • Benchmarks: comparing the sorting algorithms with BenchmarkDotNet
  • LINQ internals: rebuilding Where, Select, OrderBy, GroupBy and friends with yield
  • Dependency injection: constructor injection, lifetimes, Microsoft.Extensions.DependencyInjection
  • Testing techniques: test doubles and mocks, test data builders, testing time with TimeProvider
  • Putting it together: a small console app or web API built on these exercises
  • Concurrency: race conditions, lock vs Interlocked, a blocking queue with Monitor, run-once caching
  • Error handling: a Result<T> type, validation that collects every error, exceptions that are easy to lose
  • Reflection: custom attributes, expression trees, discovering plugins in assemblies
  • Serialization: System.Text.Json custom converters, polymorphism and source generation
  • Resource management: IDisposable and IAsyncDisposable done right, object and array pooling
  • Delegates & events: function composition and memoization, event pitfalls, a middleware pipeline
  • Parsing: a tokenizer and recursive-descent parser for arithmetic, evaluating and simplifying the syntax tree
  • Generics: variance, static generic caches, constraints with static abstract interface members
  • More data structures & algorithms: trie, union-find, ring buffer, Kruskal, backtracking, a Sudoku solver
  • State machines: table-driven with guards, a document workflow, a pure event-driven vending machine
  • Dates & times: DateOnly calendar math, business days, DST-safe time zone conversion, recurring schedules
  • Text processing: source-generated regex, a template engine, Unicode grapheme clusters, KMP search
  • Hashing: stable hashes, a hash map from scratch, Bloom filters, consistent hashing
  • Caching: expiration with TimeProvider, stampede protection, cache-aside with negative caching
  • Immutable data: persistent collections with structural sharing, snapshot-based undo, what "read-only" really means
  • I/O & binary data: a versioned file format with checksums, endianness, stream decorators, streaming processing
  • Numerics: floating-point pitfalls, exact rationals, modular arithmetic and primality testing
  • Domain modelling: strongly typed ids, value objects, money allocation, the specification pattern
  • Async coordination: async locks and events, async lazy initialisation, a lock-free stack
  • Compression & encoding: varints with ZigZag and deltas, Huffman coding, human-friendly Base32 with check symbols
  • Diffing: the Myers diff algorithm, unified diff output, applying patches that have drifted
  • Geometry & bits: convex hulls, polygons, closest pair, haversine, bit tricks, Gray and Morton codes, Held–Karp
  • Range queries: prefix sums, Fenwick and segment trees, sparse tables, sliding windows
  • Graph & text algorithms: SCCs, Bellman–Ford, Floyd–Warshall, max flow, A*, suffix arrays, Aho–Corasick, Manacher
  • More DP & randomness: knapsack, LIS, Kadane, interval scheduling, Fisher–Yates, reservoir sampling, alias tables
  • Statistics & linear algebra: Welford, HyperLogLog, count-min, regression, Gaussian elimination, PageRank
  • Reliability: token bucket, circuit breaker, bulkhead, load balancing, timing wheels, cron
  • Codecs & formats: Base64, UTF-8, percent-encoding, CSV, INI, JSON, semver, command lines
  • Simulations: Game of Life, cellular automata, minimax, mazes, flood fill, queueing
  • Functional programming: Option, trampolines, lenses, zippers, monoids, parser combinators
  • More patterns & collections: command, visitor, composite, proxy, mediator; deque, skip list, LFU, AVL tree
  • Checksums & finance: Luhn, IBAN, ISBN, Damm, loan amortization, NPV and IRR
  • Combinatorics & fuzzy matching: binomials, permutations, partitions, Catalan; Jaro–Winkler, BK-trees, MinHash
  • Search engine: tokenizing and stemming, inverted index, BM25, boolean queries, snippets, autocomplete
  • Operating systems & networking: scheduling, paging, allocators; CIDR, routing, checksums, HTTP parsing
  • Distributed systems & event sourcing: logical clocks, CRDTs, Merkle trees, 2PC; event store, projections, sagas
  • Spatial, imaging & signals: quadtrees, k-d trees, geohash; filters, dithering; FFT, DTMF, pitch detection
  • Interpreters & numerical methods: a VM, a regex engine, a Lisp; root finding, integration, ODEs, annealing
  • Security & commerce: password hashing, JWT, TOTP, sanitizing; VAT, tiered pricing, proration, FX
  • Data processing & property testing: joins, external sort, pivots, window functions; generators and shrinking
  • More dates, collections & concurrency: RRULEs, SLAs, ISO weeks; rope, bag, decrease-key heap; actors, barriers, lock striping
  • Text formatting & puzzles: case conversion, natural sort, globs, Markdown; Hanoi, word ladders, the 8-puzzle
  • More graphs, DP & compression: Euler paths, colouring, LCA; egg drop, regex DP, stock trading; LZ77, LZW, BWT
  • Ciphers & machine learning: Caesar/Vigenère attacks, RSA, Shamir, AES-GCM; k-means, naive Bayes, decision trees
  • Web & patterns: routing, content negotiation, ETags, cursors, CORS, cookies; memento, state, flyweight, bridge
  • Accounting, formats, async & numerics: ledgers, depreciation; logfmt, NDJSON, RSS; batching, keyed locks; fixed point, continued fractions
  • Testing, reflection, planning, recommendations & diagnostics: snapshot and mutation testing; mappers and diffs; CPM, Hungarian; Apriori; logging, metrics, tracing

Author

Dejan Ciev · GitHub @dejanciev-dev

If you find this useful, consider giving the repo a ⭐

About

400+ C# exercises on .NET 10 with xUnit tests: data structures, algorithms, LINQ, async, concurrency, design patterns, parsing, networking, ML basics, and more. Each one is small and runnable.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages