Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add examples for nullability and null states #1192

Open
wants to merge 7 commits into
base: draft-v8
Choose a base branch
from
Open
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 94 additions & 1 deletion standard/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -863,8 +863,101 @@ The ***default null state*** of an expression is determined by its type, and the

A diagnostic can be produced when a variable ([§9.2.1](variables.md#921-general)) of a non-nullable reference type is initialized or assigned to an expression that is maybe null when that variable is declared in text where the annotation flag is enabled.

> *Example*: Consider the following method where a parameter is nullable and that value is assigned to a non-nullable type:
>
> <!-- Example: {template:"code-in-class-lib", name:"NullableAssignment", expectedWarnings:["CS8600"]} -->
> ```csharp
> #nullable enable
> public class C
> {
> public void M(string? p)
> {
> // Assignment of maybe null value to non-nullable variable
> string s = p;
> }
> }
> ```
>
> The compiler may issue a warning where the parameter that might be null is assigned to a variable that should not be null. If the parameter is null-checked before assignment, the compiler won't issue a warning:
BillWagner marked this conversation as resolved.
Show resolved Hide resolved
BillWagner marked this conversation as resolved.
Show resolved Hide resolved
>
> <!-- Example: {template:"code-in-class-lib", name:"NullChecked"} -->
> ```csharp
> #nullable enable
> public class C
> {
> public void M(string? p)
> {
> if (p != null)
> {
> string s = p;
> // Use s
> }
> }
> }
> ```
>
> *end example*

The compiler can update the null state of a variable as part of its analysis.

> *Note*: The compiler can treat a property ([§15.7](classes.md#157-properties)) as either a variable with state, or as independent get and set accessors ([§15.7.3](classes.md#1573-accessors)). In other words, a compiler can choose if writing to a property changes the null state of reading the property.
> *Example*: The compiler may choose to update the state based on any statements in your program:
>
> <!-- Example: {template:"code-in-class-lib", name:"UpdateStates", expectedWarnings:["CS8602","CS8602"]} -->
> ```csharp
> #nullable enable
> public void M(string? p)
> {
> // p is maybe-null
> int length = p.Length;
>
> // p is not null.
> string s = p;
>
> if (s != null)
> {
> int l2 = s.Length;
> }
> // s is maybe null
> int l3 = s.Length;
> }
> ```
>
> In the previous example, the compiler may decide that after the statement `int length = p.Length;`, the null-state of `p` is not-null. If it were null, that statement would have thrown a `NullReferenceException`. Later in the method, the code checks that `s` is not a null reference. The null-state of `s` can change to maybe null after the null-checked block closes. The compiler can infer that `s` is maybe null because the code was written to assume that it might have been null. *end example*
<!-- markdownlint-disable MD028 -->

<!-- markdownlint-enable MD028 -->
> *Example*: The compiler can treat a property ([§15.7](classes.md#157-properties)) as either a variable with state, or as independent get and set accessors ([§15.7.3](classes.md#1573-accessors)). In other words, a compiler can choose whether writing to a property changes the null state of reading the property, or if reading a property changes the null state of that property.
>
> <!-- Example: {template:"standalone-console", name:"NullPropertyAnalysis"} -->
> ```csharp
> class Test
> {
> private string? _field;
> public string? DisappearingProperty
> {
> get
> {
> string tmp = _field;
> _field = null;
> return tmp;
> }
> set
> {
> _field = value;
> }
> }
>
> static void Main()
> {
> var t = new Test();
> if (t.DisappearingProperty != null)
> {
> int len = t.DisappearingProperty.Length;
> }
> }
> }
> ```
>
> In the previous example, the backing field for the `DisappearingProperty` is set to null when it is read. However, a compiler may assume that reading a property doesn't change the null state of that expression. *end example*

***End of conditionally normative text***
Loading