可空数组以及我们为什么需要它们

Nullable Array and Why Do We Need Them

我看到这样的代码,我将其理解为使数组可为空,但我不明白为什么我们需要它,因为数组是引用类型,所以它们已经可以为空。

那么,我的问题是我们为什么需要这个?

private readonly decimal?[] _amounts = new decimal?[_count];

声明为decimal?[]表示数组包含的元素可以是null或非空.

如果不使其可空,数组可以存储的元素不能null.

换句话说,decimal?[] 读作 "an array of nullable decimals"。 ? 指的是数组可以包含的元素,而不是数组本身,因为所有数组都是引用类型。

这里的可空说明符不是指数组本身,而是指数组的内容。正如您所说的那样,数组本身就是一个引用类型,因此,它总是可以为空的(至少在 C#8 之前是这样)。

几个不同的例子:

decimal[] nonNullable = new decimal[2];
nonNullable[0] = 1;             //OK, a non null item
nonNullable[1] = null;          //Compile error: array doesn't accepts nulls
nonNullable = null;             //OK, set the array reference to null

decimal?[] nullable = new decimal?[2];
nullable[0] = 1;                //OK, a non null item
nullable[1] = null;             //OK, a null item (actually, a Nullable<decimal> instance)
nullable = null;                //OK, set the array reference to null

数组对象本身与数组元素之间存在差异。当您使用 decimal?[] 时,您正在声明一个数组,其元素是可为空的 decimal 值。如果您要使用 decimal[]?(我不确定这是有效的语法,但只是为了解释目的,假设它是有效的)您将声明一个可能引用数组或可能不引用任何内容的变量。后者是您描述的无用情况,因为就像您说的(至少在旧版本的 C# 中)所有数组变量都是已经可以设置为 null.

的引用变量

为了阐明区别,请考虑 Alejandro 发布的代码,以及以下代码:

decimal[]? reallyNullable = null;

Array.Sort(reallyNullable); // ArgumentNullException -- there is no array here
Array.Sort(nullable); // OK, assuming null can be compared to decimal.

之所以最后一行没问题,是因为这里实际上引用了一个数组对象。唯一为空的是其中的一些值。

值得一提的是,从 C# 8.0 开始,您可以拥有 可为空的引用类型https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/nullable-reference-types

但正如其他人提到的那样:

private readonly decimal?[] _amounts = new decimal?[_count];

表示数组中的值类型元素可以为空。 decimal 是值类型,通常你不能将 null 赋值给它,但如果你有 decimal? 那么你可以。

启用 C# 8.0 和可空引用类型功能后,如果要将引用类型赋值为空,则应将引用类型声明为可空引用类型,否则默认情况下会收到编译器警告。您可以这样声明:

private decimal?[]? _amounts;

现在这意味着数组中的两个元素都可以为空并且整个数组(_amounts 变量)可以为空。

所以一般来说,元素值类型?之后和[]->SomeValueType?[]之前的问号表示数组中的元素可以为空。从 C# 8.0(在项目中启用了功能)数组类型 SomeArrayType[] -> SomeArrayType[]? 之后的问号 ? 意味着您可以将 null 分配给包含对数组的引用的变量。