nullable-reference-disciplinelisted
Install: claude install-skill Sarmkadan/dotnet-senior-skills
# Nullable Reference Discipline
## Baseline
`<Nullable>enable</Nullable>` project-wide plus `<WarningsAsErrors>nullable</WarningsAsErrors>`. Warnings-as-suggestions rot in a week. For gradual migration, enable per-file with `#nullable enable` starting from the leaves (models, utilities) upward, and never add new files without it.
## The annotation is a contract, not a wish
- `string Name` means never null - and the type must make it true: initialized at construction (`required`, constructor parameter) or the annotation is a lie the compiler will now defend.
- `string? Name` means callers MUST handle null. Do not add `?` to silence a warning when the value is logically always present - fix the initialization instead.
```csharp
// WRONG: lying to the compiler to make the warning go away
public string Email { get; set; } = null!;
// RIGHT: the contract is enforced at construction
public required string Email { get; set; }
```
`= null!` is acceptable in exactly two places: EF Core navigation properties (materializer sets them) and DI-populated framework hooks. Each occurrence outside those needs a comment saying why.
## Null-forgiving operator audit
Every `!` is a claim: "I know more than the flow analysis." In review, verify the claim:
- `dict[key]!` after `ContainsKey` - fine, but `TryGetValue` removes the need.
- `FirstOrDefault()!` - almost always wrong; if absence is impossible use `First()` (fails loudly at the right place), if possible, handle it.
- `!` on deserial