Modern C#
Model values, handle missing data, and express intent with modern C#.
- Records and value equality
Describe a value with a record and compare its contents.
Core ideas · 10 min - Nullable values
Represent an absent measurement without inventing a number.
Core ideas · 10 min - Property patterns
Choose a result from several fields of a value.
Core ideas · 10 min - Switch expressions
Return one value from an exhaustive set of cases.
Core ideas · 10 min - Tuples and deconstruction
Return two related results without an output parameter.
Working with data · 10 min - Init-only properties
Construct a value and restrict later assignment.
Working with data · 10 min - Generic methods
Preserve a caller’s type through reusable logic.
Working with data · 10 min - Interface contracts
Call different implementations through one useful contract.
Working with data · 10 min - Value copies and references
Predict whether assignment copies data or shares an object.
Putting it together · 10 min - Iterator methods
Produce sequence elements when a consumer requests them.
Putting it together · 10 min - Flags and explicit checks
Combine independent options and test whether one is present.
Putting it together · 10 min - Validation as a result
Make expected input failures visible in a method contract.
Putting it together · 10 min - Guard clauses and precise exceptions
Reject invalid inputs before they reach the main calculation.
Deeper practice · 18 min - Required members are a construction contract
Separate compiler-enforced initialization from runtime validation.
Deeper practice · 18 min - Record copies and shared collections
Inspect equality and mutation when records contain reference members.
Deeper practice · 18 min - Readonly record structs and value copies
Use small immutable values without confusing them with shared objects.
Deeper practice · 18 min - Defensive copies at ownership boundaries
Keep a caller-owned array from rewriting an established snapshot.
Deeper practice · 18 min - Virtual behavior through a base reference
Follow runtime dispatch while keeping the public contract stable.
Deeper practice · 18 min - Strategy functions with delegates
Pass a calculation policy instead of duplicating an entire workflow.
Deeper practice · 18 min - Generic constraints express capabilities
Require comparison explicitly before writing a generic minimum.
Deeper practice · 18 min - Covariant read-only views
Read derived values through a base interface without promising writes.
Applied techniques · 18 min - Explicit interface implementations
Resolve two contracts without making their meanings ambiguous.
Applied techniques · 18 min - Exception filters preserve diagnostic distinctions
Handle one expected failure while letting unrelated failures remain visible.
Applied techniques · 18 min - Deterministic cleanup with using
Release an owned resource when control leaves its scope.
Applied techniques · 18 min - List patterns describe sequence shapes
Recognize an array shape before reading its selected elements.
Applied techniques · 18 min - Ranges and spans without new array storage
Read a portion of a buffer while respecting shared lifetime and mutation.
Applied techniques · 18 min - Extension methods remain ordinary static behavior
Add a readable operation without changing the represented type.
Applied techniques · 18 min - Closures capture variables, not frozen values
Predict a delegate after the state it references changes.
Applied techniques · 18 min - Collection expressions need a target
Choose array, list, and read-only interface targets deliberately.
Current C# & .NET · 12 min - Spread elements materialize a sequence
Track spread enumeration and distinguish a shallow snapshot from a live query.
Current C# & .NET · 12 min - Primary constructors in ordinary classes
Use a primary-constructor parameter without assuming record properties.
Current C# & .NET · 12 min - Aliases name tuple and array types
Separate source-level aliases from new nominal types or copied storage.
Current C# & .NET · 12 min - Generic math through static contracts
Call numeric identities and operators through INumber<T> constraints.
Current C# & .NET · 12 min - Params collections without an array contract
Accept a C# 13 params ReadOnlySpan<int> with empty and existing-array cases.
Current C# & .NET · 12 min - FrozenDictionary fixes lookup policy
Freeze a read-heavy map with an explicit comparer and detached scalar values.
Current C# & .NET · 12 min - SearchValues reuses a search set
Find any separator with a reusable search set and explicit not-found handling.
Current C# & .NET · 12 min - C# 14 extension blocks and properties
Compare an ordinary helper with a real extension-property project for .NET 10.
C# 14 / .NET 10 — external projects · 15 min - C# 14 field-backed property validation
Compare explicit backing storage with a real field-keyword accessor.
C# 14 / .NET 10 — external projects · 15 min - C# 14 null-conditional assignment
Observe conditional right-side evaluation with guards and a real C# 14 project.
C# 14 / .NET 10 — external projects · 15 min - C# 14 nameof accepts unbound generics
Distinguish a compile-time display name from reflection type identity.
C# 14 / .NET 10 — external projects · 15 min - C# 14 span conversions at call boundaries
Compare explicit span calls with generic extension receiver conversions.
C# 14 / .NET 10 — external projects · 15 min - C# 14 inferred lambda parameter modifiers
Keep a real out-parameter delegate while omitting redundant types externally.
C# 14 / .NET 10 — external projects · 15 min - C# 14 partial constructors and events
Compare one complete type with defining and implementing declarations.
C# 14 / .NET 10 — external projects · 15 min - C# 14 user-defined compound assignment
Observe in-place reference mutation separately from replacement addition.
C# 14 / .NET 10 — external projects · 15 min - .NET 10 file-based apps and build directives
Run an actual SDK-managed single-file app externally; compare its domain rule here.
C# 14 / .NET 10 — external projects · 15 min - C# 13 ref-struct scope before await
Finish span work before suspension and carry an ordinary result forward.
Current C# & .NET · 12 min