Skip to content

Commit 03a48c7

Browse files
committed
Another round of edits.
1 parent 9d6da38 commit 03a48c7

2 files changed

Lines changed: 27 additions & 22 deletions

File tree

docs/csharp/fundamentals/null-safety/resolve-warnings.md

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,43 +15,34 @@ ai-usage: ai-assisted
1515
1616
When you enable nullable reference types, the compiler issues warnings everywhere your code's behavior doesn't match its annotations. Most warnings fall into a small set of patterns. Once you recognize the pattern, the fix is usually one of five techniques:
1717

18-
- Configure the nullable context.
1918
- Add a null check.
2019
- Add or remove a `?` or `!` annotation.
2120
- Add an attribute that describes the null contract.
2221
- Initialize variables correctly.
22+
- Configure the nullable context.
2323

24-
This article walks through each technique with a representative example. The goal isn't to silence warnings; it's to make the code's null-handling intent explicit so the compiler reaches the same conclusions you do.
25-
26-
## Configure the nullable context
27-
28-
The first warnings you see in an existing project often have nothing to do with your code's logic. They're about the nullable context itself:
29-
30-
- The annotation `?` is used while annotations are disabled.
31-
- A `<Nullable>` value isn't recognized.
32-
- A `#nullable` directive is malformed.
24+
This article walks through each technique with a representative example. The goal isn't to silence warnings. It's to make the code's null-handling intent explicit so the compiler reaches the same conclusions you do.
3325

34-
Enable the feature project-wide in your `.csproj`:
26+
## Null-state: what the compiler tracks
3527

36-
:::code language="xml" source="snippets/resolve-warnings/project-snippet.xml":::
28+
Before you look at the techniques, it helps to know how the compiler tracks potential null-state violations. As it reads your code, the compiler keeps track of each expression's *null-state*: its analysis about whether the expression might be `null` at that point in the code. The null-state is one of two values:
3729

38-
Or scope it to part of a file with a [preprocessor directive](../../language-reference/preprocessor-directives.md) (a line starting with `#` that gives instructions to the compiler instead of producing executable code):
30+
- *not-null* — the compiler can prove the expression isn't `null` here. You can safely use it without a check.
31+
- *maybe-null* — the compiler can't rule out `null`. Using the expression without checking it produces a warning.
3932

40-
:::code language="csharp" source="snippets/resolve-warnings/Program.cs" id="NullableDirective":::
41-
42-
The context has two independent flags. The *annotation* flag controls whether `?` and `!` are meaningful in declarations. The *warning* flag controls whether the compiler emits diagnostics. You can enable each independently. Enabling warnings while leaving annotations off lets you address null-handling bugs before you take on annotating types. Enabling annotations while leaving warnings off lets you express your design intent in the API surface without producing diagnostics in implementation code that isn't ready yet. Either combination can be the right choice for a project at a given stage. For the migration trade-offs, see [Nullable migration strategies](../../advanced-topics/update-applications/nullable-migration-strategies.md).
33+
A variable's null-state changes as the compiler follows your code. A method that might return `null` produces a *maybe-null* result. An `if (x is not null)` check narrows `x` to *not-null* inside the `if` block. The warnings you see are the compiler telling you it determined an expression is in a *maybe-null* state and you're about to use it as if it were *not-null*. Each technique in the rest of this article is a different way to give the compiler the information it needs to ensure an expression is *not-null* before you use it.
4334

4435
## Add a null check
4536

4637
The most common warning is *possible dereference of null*. The compiler tracked a variable's null-state to *maybe-null* and saw the variable used without a check:
4738

4839
:::code language="csharp" source="snippets/resolve-warnings/Program.cs" id="DereferenceWarning":::
4940

50-
The fix is usually a *guard clause*. A *guard clause* is a check at the top of a method or block that returns or throws when an input is invalid, leaving only the safe path to continue. Once the check runs, the compiler updates the variable's null state to *not-null* on the safe path:
41+
The fix is usually a *guard clause*. A *guard clause* is a check at the top of a method or block that returns or throws when an input is invalid. Only the safe path continues. Once the check runs, the compiler updates the variable's null state to *not-null* on the safe path:
5142

5243
:::code language="csharp" source="snippets/resolve-warnings/Program.cs" id="DereferenceFixed":::
5344

54-
[Pattern matching](../../language-reference/operators/patterns.md) (expressions such as `is null` or `is { } value` that test the shape of a value), `??`, and `??=` produce the same effect:
45+
[Pattern matching](../../language-reference/operators/patterns.md) (expressions such as `is null` or `is { } value` that test the shape of a value), `??`, and `??=` include null checks:
5546

5647
:::code language="csharp" source="snippets/resolve-warnings/Program.cs" id="NullOperatorsFix":::
5748

@@ -63,8 +54,8 @@ For an in-depth tour of the operators, see [Null operators](null-operators.md).
6354

6455
The compiler also warns you when your code assigns a *maybe-null* expression to a non-nullable variable. That warning means one of two things:
6556

66-
- The variable shouldn't be non-nullable. Add a `?` to the type.
67-
- The expression shouldn't be maybe-null. Annotate the API that produced it.
57+
- The variable should allow null values. In that case, add a `?` to the type.
58+
- The expression never produces a null value. Annotate the API that produced it.
6859

6960
:::code language="csharp" source="snippets/resolve-warnings/Program.cs" id="AssignmentWarning":::
7061

@@ -114,14 +105,28 @@ You have several ways to address it. Pick the one that best matches your design
114105
:::code language="csharp" source="snippets/resolve-warnings/Program.cs" id="InitializedMember":::
115106

116107
> [!TIP]
117-
> Choose this technique only when the type has a genuinely good default value: one that's a valid, fully-functional instance for callers to consume. Examples include <xref:System.String.Empty?displayProperty=nameWithType> or an empty collection. Don't invent a *sentinel* (a placeholder value such as `"N/A"`, `"unknown"`, or `-1` that you treat as "no value") to stand in for `null`: it silences the warning, but every caller has to know about and check for the sentinel, and the type system can't help. When no good default exists, make the property nullable instead.
108+
> Choose this technique only when the type has a genuinely good default value: one that's a valid, fully-functional instance for callers to consume. Examples include empty collections. Don't invent a *sentinel* (a placeholder value such as <xref:System.String.Empty?displayProperty=nameWithType>, "N/A"`, `"unknown"`, or `-1` that you treat as "no value") to stand in for `null`: it silences the warning, but every caller has to know about and check for the sentinel, and the type system can't help. When no good default exists, make the property nullable instead.
118109
119110
**Make the property nullable.** When the value really might be missing, change the type to nullable:
120111

121112
:::code language="csharp" source="snippets/resolve-warnings/Program.cs" id="NullableMember":::
122113

123114
If a helper method initializes the member, annotate the helper with <xref:System.Diagnostics.CodeAnalysis.MemberNotNullAttribute> so the compiler can credit calls to it.
124115

116+
## Configure the nullable context
117+
118+
New C# projects enable nullable reference types by default, so most code you write or read already has the feature turned on. You generally don't need to configure anything. If you're curious whether a project has it enabled, or you need to change the setting, look for the `<Nullable>` element in the `.csproj`:
119+
120+
:::code language="xml" source="snippets/resolve-warnings/project-snippet.xml":::
121+
122+
The supported values are `enable` (the default for new projects), `disable`, `warnings`, and `annotations`. If the element is missing, the project uses whatever default the SDK and target framework set.
123+
124+
To change the setting for part of a file without affecting the rest of the project, use a [preprocessor directive](../../language-reference/preprocessor-directives.md) (a line starting with `#` that gives instructions to the compiler instead of producing executable code):
125+
126+
:::code language="csharp" source="snippets/resolve-warnings/Program.cs" id="NullableDirective":::
127+
128+
The `warnings` and `annotations` values turn on only part of the feature, and they're primarily useful in advanced scenarios such as migrating a large existing codebase one piece at a time. For those trade-offs, see [Nullable migration strategies](../../advanced-topics/update-applications/nullable-migration-strategies.md). For everyday work, `enable` and `disable` are the two values you need.
129+
125130
## Where to go next
126131

127132
When a warning doesn't fit any of these patterns, the [Resolve nullable warnings](../../language-reference/compiler-messages/nullable-warnings.md) reference article lists the technique for every CS86xx warning the compiler emits.

docs/csharp/fundamentals/null-safety/snippets/resolve-warnings/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public class PersonRequired
132132
// <InitializedMember>
133133
public class PersonInitialized
134134
{
135-
public string Name { get; set; } = string.Empty;
135+
public string Name { get; set; } = "John Doe";
136136
}
137137
// </InitializedMember>
138138

0 commit comments

Comments
 (0)