Skip to content

Commit

Permalink
Freshness pass and bug fixes: Nullable reference types (#43914)
Browse files Browse the repository at this point in the history
* Update notes on annotations

Update the article to use the language adopted by the C# standards committee to describe the nullable context, and the null state of any variables.

* freshness pass and bug fixes

Fixes #21941: Add description of the default values for arrays of reference types.
Fixes #30348: Edit pass
Fixes #33667:  Update the description of the nullable context to match the language used in the C# 8 draft standard
Fixes #36767: Add language on declaring a non-null array of nullable reference types and a nullable array of non-nullable reference types.

Also, perform a general edit pass.

* fix warnings

* Apply suggestions from code review

Co-authored-by: Andy (Steve) De George <[email protected]>

---------

Co-authored-by: Andy (Steve) De George <[email protected]>
  • Loading branch information
BillWagner and adegeo authored Dec 13, 2024
1 parent 4c158be commit 8995edc
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 52 deletions.
24 changes: 21 additions & 3 deletions docs/csharp/language-reference/builtin-types/arrays.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Arrays"
title: "The array reference type"
description: Store multiple variables of the same type in an array data structure in C#. Declare an array by specifying a type or specify Object to store any type.
ms.date: 08/24/2023
ms.date: 12/09/2024
helpviewer_keywords:
- "arrays [C#]"
- "C# language, arrays"
Expand All @@ -26,6 +26,24 @@ You can store multiple variables of the same type in an array data structure. Yo
type[] arrayName;
```

An array is a reference type, so the array can be a [nullable reference](../../nullable-references.md) type. The element types might be reference types, so an array can be declared to hold nullable reference types. The following example declarations show the different syntax used to declare the nullability of the array or the elements:

```csharp
type?[] arrayName; // non nullable array of nullable element types.
type[]? arrayName; // nullable array of non-nullable element types.
type?[]? arrayName; // nullable array of nullable element types.
```

Uninitialized elements in an array are set to the default value for that type:

```csharp
int[] numbers = new int[10]; // All values are 0
string[] messages = new string[10]; // All values are null.
```

> [!IMPORTANT]
> In the preceding example, even though the type is `string[]`, an array of non-nullable strings, the default value for each element is null. The best way to initialize an array to non-null values is to use a [collection expressions](../operators/collection-expressions.md).
An array has the following properties:

- An array can be [single-dimensional](#single-dimensional-arrays), [multidimensional](#multidimensional-arrays), or [jagged](#jagged-arrays).
Expand Down Expand Up @@ -67,7 +85,7 @@ You can pass an initialized single-dimensional array to a method. In the followi
## Multidimensional arrays
Arrays can have more than one dimension. For example, the following declarations create four arrays: two have two dimensions, two have three dimensions. The first two declarations declare the length of each dimension, but don't initialize the values of the array. The second two declarations use an initializer to set the values of each element in the multidimensional array.
Arrays can have more than one dimension. For example, the following declarations create four arrays. Two arrays have have two dimensions. Two arrays have three dimensions. The first two declarations declare the length of each dimension, but don't initialize the values of the array. The second two declarations use an initializer to set the values of each element in the multidimensional array.
:::code language="csharp" source="./snippets/shared/Arrays.cs" id="MultiDimensionalArrayDeclaration":::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ The **Nullable** option lets you specify the nullable context. It can be set in
<Nullable>enable</Nullable>
```

The argument must be one of `enable`, `disable`, `warnings`, or `annotations`. The `enable` argument enables the nullable context. Specifying `disable` will disable the nullable context. When you specify the `warnings` argument, the nullable warning context is enabled. When you specify the `annotations` argument, the nullable annotation context is enabled. The values are described and explained in the article on [Nullable contexts](../../nullable-references.md#nullable-contexts). You can learn more about the tasks involved in enabling nullable reference types in an existing codebase in our article on [nullable migration strategies](../../nullable-migration-strategies.md).
The argument must be one of `enable`, `disable`, `warnings`, or `annotations`. The `enable` argument enables the nullable context. Specifying `disable` will disable the nullable context. When you specify the `warnings` argument, the nullable warning context is enabled. When you specify the `annotations` argument, the nullable annotation context is enabled. The values are described and explained in the article on [Nullable contexts](../../nullable-references.md#nullable-context). You can learn more about the tasks involved in enabling nullable reference types in an existing codebase in our article on [nullable migration strategies](../../nullable-migration-strategies.md).

> [!NOTE]
> When there's no value set, the default value `disable` is applied, however the .NET 6 templates are by default provided with the **Nullable** value set to `enable`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ The `where` clause can specify that the type is a `class` or a `struct`. The `st

In a nullable context, the `class` constraint requires a type to be a non-nullable reference type. To allow nullable reference types, use the `class?` constraint, which allows both nullable and non-nullable reference types.

The `where` clause can include the `notnull` constraint. The `notnull` constraint limits the type parameter to non-nullable types. The type can be a [value type](../builtin-types/value-types.md) or a non-nullable reference type. The `notnull` constraint is available for code compiled in a [`nullable enable` context](../../nullable-references.md#nullable-contexts). Unlike other constraints, if a type argument violates the `notnull` constraint, the compiler generates a warning instead of an error. Warnings are only generated in a `nullable enable` context.
The `where` clause can include the `notnull` constraint. The `notnull` constraint limits the type parameter to non-nullable types. The type can be a [value type](../builtin-types/value-types.md) or a non-nullable reference type. The `notnull` constraint is available for code compiled in a [`nullable enable` context](../../nullable-references.md#nullable-context). Unlike other constraints, if a type argument violates the `notnull` constraint, the compiler generates a warning instead of an error. Warnings are only generated in a `nullable enable` context.

The addition of nullable reference types introduces a potential ambiguity in the meaning of `T?` in generic methods. If `T` is a `struct`, `T?` is the same as <xref:System.Nullable%601?displayProperty=nameWithType>. However, if `T` is a reference type, `T?` means that `null` is a valid value. The ambiguity arises because overriding methods can't include constraints. The new `default` constraint resolves this ambiguity. You add it when a base class or interface declares two overloads of a method, one that specifies the `struct` constraint, and one that doesn't have either the `struct` or `class` constraint applied:

Expand Down
2 changes: 1 addition & 1 deletion docs/csharp/language-reference/operators/null-forgiving.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ helpviewer_keywords:
---
# ! (null-forgiving) operator (C# reference)

The unary postfix `!` operator is the null-forgiving, or null-suppression, operator. In an enabled [nullable annotation context](../../nullable-references.md#nullable-contexts), you use the null-forgiving operator to suppress all nullable warnings for the preceding expression. The unary prefix `!` operator is the [logical negation operator](boolean-logical-operators.md#logical-negation-operator-). The null-forgiving operator has no effect at run time. It only affects the compiler's static flow analysis by changing the null state of the expression. At run time, expression `x!` evaluates to the result of the underlying expression `x`.
The unary postfix `!` operator is the null-forgiving, or null-suppression, operator. In an enabled [nullable annotation context](../../nullable-references.md#nullable-context), you use the null-forgiving operator to suppress all nullable warnings for the preceding expression. The unary prefix `!` operator is the [logical negation operator](boolean-logical-operators.md#logical-negation-operator-). The null-forgiving operator has no effect at run time. It only affects the compiler's static flow analysis by changing the null state of the expression. At run time, expression `x!` evaluates to the result of the underlying expression `x`.

For more information about the nullable reference types feature, see [Nullable reference types](../builtin-types/nullable-reference-types.md).

Expand Down
Loading

0 comments on commit 8995edc

Please sign in to comment.