Part 4 · 1 chapters · ~8 min

Idioms

Nullable reference types and warnings as errors, records versus classes, constructor injection and service lifetimes (captive dependencies), exceptions versus result types, LINQ readability and deferred execution pitfalls, IDisposable patterns, naming conventions, .editorconfig and Roslyn analyzers, and common review comments.

5

Patterns that age well

code
<PropertyGroup>
  <Nullable>enable</Nullable>
  <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
  <AnalysisLevel>latest-recommended</AnalysisLevel>
</PropertyGroup>

builder.Services.AddScoped<ILedger, Ledger>();            // per request
builder.Services.AddSingleton<IFxRates, CachedFxRates>();  // must not depend on scoped services (captive dependency)

// deferred execution: this query runs twice
var pending = db.Payouts.Where(p => p.State == "pending");
if (pending.Any()) foreach (var p in pending) …            // two round trips; use ToListAsync once

public abstract record TransferResult { public sealed record Ok(Transfer T) : TransferResult; public sealed record InsufficientFunds(long Available) : TransferResult; }
IDIOMATIC C#
what reviewers look for
nullable on<Nullable>enable</Nullable> and nowarnings ignored.records for dataImmutable DTOs and value objects;classes for behaviour.dependency injectionConstructor injection via thebuilt-in container.Result types or exceptionsExceptions for the exceptional;results for domain outcomes.LINQ with careReadable queries; watch multipleenumeration and N+1.analyzers.editorconfig, Roslyn analyzers,TreatWarningsAsErrors.
swipe the figure sideways, or tap expand for full screen
1/4
safety settings
Enable nullable reference types and treat warnings as errors in new projects; most null bugs then fail the build.
nullable + warnings as errorsbugs at build time