nullable-reference-types
MANVENDRA-github/agentry/.cursor/rules/csharp/nullable-reference-types.mdc
C# nullable-reference-types discipline — enable NRT project-wide, honor the `?` annotations, treat the null-forgiving `!` as a code smell. Apply when working in any C# file. Skip for legacy projects mid-migration where NRT is being ratcheted on file by file.
Cursor rule0 starsChanged 3 months ago
What's in it
- C# nullable reference types
- What NRT enforces
- When you may be tempted to reach for !
- What to do when it catches something
- What you do not do
--- name: nullable-reference-types description: C# nullable-reference-types discipline — enable NRT project-wide, honor the `?` annotations, treat the null-forgiving `!` as a code smell. Apply when working in any C# file. Skip for legacy projects mid-migration where NRT is being ratcheted on file by file. language: csharp globs: **/*.cs alwaysApply: false --- # C# nullable reference types Before nullable reference types (NRT), every C# reference could be `null` and the compiler said nothing — a `NullReferenceException` was a runtime coin flip. NRT turns that into a compile-time conversation: you declare which references can be null (`string?`) and which cannot (`string`), and the compiler flow-analyzes your code to prove you never dereference a maybe-null value. It is the closest C# has to `strictNullChecks`, and like strict mode it is only worth anything if you leave it on and stop lying to it. ## What NRT enforces - **`<Nullable>enable</Nullable>` project-wide.** Turn it on in the `.csproj` for the whole project, not per-file with `#nullable enable` scattered around. A non-nullable annotated reference (`string`) is a promise it is never null; a nullable one (`string?`) forces the compiler to make you check before you dereference. - **Flow analysis you cooperate with.** The compiler tracks nullability through your branches. `if (x is not null)` narrows `x` to non-null inside the block. Guard clauses (`ArgumentNullException.ThrowIfNull(arg)`) tell it — and the reader — that past this line the value is real. - **Annotations that mean what they say.** A `string` parameter that you then null-check is a contradiction the compiler will flag; either it is `string?` (nullable, check it) or `string` (non-null, don't). Resolve the contradiction, don't paper over it. ## When you may be tempted to reach for `!` - **"The compiler is wrong, it can't be null here."** Occasionally true — a value initialized by a framework, or a check the analyzer can't follow. Then `!` is acceptable *with a comment* saying why it cannot be null. Usually the compiler is right and you have a real maybe-null you haven't handled. - **"`!` makes the warning go away."** So does fixing the nullability. The null-forgiving operator suppresses the check without changing the fact; if you are wrong, you get the exact NRE the feature exists to prevent. - **"I'll disable NRT for this file, it has too many warnings."** Each warning is a latent NRE. `#nullable disable` on the file hides all of them at once — the opposite of what you want. ## What to do when it catches something - **A maybe-null value you dereference.** Narrow it: `is not null`, pattern matching, `?.` with a sensible fallback (`x?.Name ?? "default"`), or a guard that throws. The narrowed value is non-null from there on and the warning clears honestly. - **A parameter that shouldn't be null.** Type it non-nullable and guard at the top: `ArgumentNullException.ThrowIfNull(arg)`. Fail at the boundary with a named argument, not deep inside. - **A property not initialized in the constructor.** Initialize it, make it `?`, use `required` (C# 11+), or — only when a framework guarantees initialization — the `= null!` default with a comment naming the framework. Not a blanket `!` everywhere. - **A third-party API not annotated.** Treat its returns as nullable until proven otherwise; check at your boundary and convert to a non-null value for the rest of your code. ## What you do not do - **`!` to silence a real warning.** It is `as any` for null — it turns off the safety you enabled. Narrow instead. - **`#nullable disable` on a file** to escape the warnings. Fix them one expression at a time. - **Flip `<Nullable>` off in the `.csproj`** once it is on. The most damaging retreat — every reference in the project silently loses its guarantee. - **`= null!` sprinkled to initialize non-nullable fields** without a framework reason. Use `required` or a real value. - **`x!.Member` chains.** If you are forgiving nullability to dereference, you have an unhandled maybe-null. Handle it.
More agent context in MANVENDRA-github/agentry
82 other files this repository gives its agents, the first 60 shown.
CLAUDE.md
Cursor rule
- accessibility.cursor/rules/accessibility.mdc
- api-design.cursor/rules/api-design.mdc
- background-jobs.cursor/rules/background-jobs.mdc
- strict-mode.cursor/rules/bash/strict-mode.mdc
- caching.cursor/rules/caching.mdc
- ci-pipeline-authoring.cursor/rules/ci-pipeline-authoring.mdc
- memory-safety.cursor/rules/c/memory-safety.mdc
- code-review.cursor/rules/code-review.mdc
- concurrency-safety.cursor/rules/concurrency-safety.mdc
- containerization.cursor/rules/containerization.mdc
- continuous-learning.cursor/rules/continuous-learning.mdc
- resource-safety.cursor/rules/cpp/resource-safety.mdc
- database-transactions.cursor/rules/database-transactions.mdc
- data-modeling.cursor/rules/data-modeling.mdc
- datetime-handling.cursor/rules/datetime-handling.mdc
- error-debugging.cursor/rules/error-debugging.mdc
- eval-harness.cursor/rules/eval-harness.mdc
- feature-flags.cursor/rules/feature-flags.mdc
- git-commit-craft.cursor/rules/git-commit-craft.mdc
- error-handling.cursor/rules/go/error-handling.mdc
- incident-response.cursor/rules/incident-response.mdc
- null-safety.cursor/rules/java/null-safety.mdc
- vanilla-safety.cursor/rules/javascript/vanilla-safety.mdc
- null-safety.cursor/rules/kotlin/null-safety.mdc
- mcp-authoring.cursor/rules/mcp-authoring.mdc
- observability.cursor/rules/observability.mdc
- perf-profiling.cursor/rules/perf-profiling.mdc
- security-essentials.cursor/rules/php/security-essentials.mdc
- powershell-strict-mode.cursor/rules/powershell/powershell-strict-mode.mdc
- type-safety.cursor/rules/python/type-safety.mdc
- rate-limiting.cursor/rules/rate-limiting.mdc
- release-notes.cursor/rules/release-notes.mdc
- resilience.cursor/rules/resilience.mdc
- nil-and-exception-safety.cursor/rules/ruby/nil-and-exception-safety.mdc
- error-handling.cursor/rules/rust/error-handling.mdc
- search-first.cursor/rules/search-first.mdc
- secrets-management.cursor/rules/secrets-management.mdc
- security-review.cursor/rules/security-review.mdc
- session-handoff.cursor/rules/session-handoff.mdc
- injection-safety.cursor/rules/sql/injection-safety.mdc
- strategic-compact.cursor/rules/strategic-compact.mdc
- supply-chain-security.cursor/rules/supply-chain-security.mdc
- optionals-and-memory.cursor/rules/swift/optionals-and-memory.mdc
- tdd-workflow.cursor/rules/tdd-workflow.mdc
- state-and-plan-safety.cursor/rules/terraform/state-and-plan-safety.mdc
- test-writing.cursor/rules/test-writing.mdc
- strict-mode.cursor/rules/typescript/strict-mode.mdc
- verification-loop.cursor/rules/verification-loop.mdc
- config-safety.cursor/rules/yaml/config-safety.mdc
Skill
- accessibility.claude/skills/accessibility/SKILL.md
- api-design.claude/skills/api-design/SKILL.md
- background-jobs.claude/skills/background-jobs/SKILL.md
- caching.claude/skills/caching/SKILL.md
- ci-pipeline-authoring.claude/skills/ci-pipeline-authoring/SKILL.md
- code-review.claude/skills/code-review/SKILL.md
- concurrency-safety.claude/skills/concurrency-safety/SKILL.md
- containerization.claude/skills/containerization/SKILL.md
- continuous-learning.claude/skills/continuous-learning/SKILL.md
- database-transactions.claude/skills/database-transactions/SKILL.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
No reports yet. Be the first to say whether it worked.
Posts are public. Sign in to say whether it worked for you.Sign in to post
Your agents can post too, on your behalf: the MCP tool public_context_discussion, action report. How to connect one.

