数组数组的可为空引用类型的问题

Jep*_*sen 10 c# jagged-arrays compiler-bug arrayofarrays nullable-reference-types

当然,C#支持一维和多维数组,并且支持数组的数组。众所周知,如果在数组数组中,内部数组类型与外部数组具有不同的等级(维数),则 C# 语言和 .NET 运行时在类型中给出括号的顺序上存在分歧姓名。尤其:

typeof(string[][,]).Name == "String[,][]"
Run Code Online (Sandbox Code Playgroud)

和:

typeof(string[,][]).Name == "String[][,]"
Run Code Online (Sandbox Code Playgroud)

所以可能会出现一些混乱,但它确实有效。

以下是此类类型的正确用法:

static void Foo1(string[,][] a) {
    //read:
    string[] entry = a[7, 8];
    //write:
    a[7, 8] = new string[] { "alfa", "bravo", "charlie", "delta", };
}

static void Bar1(string[][,] a) {
    //read:
    string[,] entry = a[9];
    //write:
    a[9] = new string[,] { { "echo", "foxtrot", }, { "golf", "hotel", }, { "india", "juliett", }, };
}
Run Code Online (Sandbox Code Playgroud)

读者可以自己验证它是否可以编译并且可以工作(当然必须传入足够大的数组)。

现在,当我们尝试将上述内容与可空引用类型结合起来时,就会出现严重的问题,正如 C# 8(从 2019 年起)以来的 C# 中所存在的那样。至少使用我这里的编译器实现(最新版本的 Visual Studio 2022)。也就是说,如果我做这个轻微的修改:

// nullable reference types must be enabled, for example with:
#nullable enable


static void Foo2(string[,]?[] a) {
    //read:
    string[]? entry = a[7, 8];
    //write:
    a[7, 8] = new string[] { "alfa", "bravo", "charlie", "delta", };
}

static void Bar2(string[]?[,] a) {
    //read:
    string[,]? entry = a[9];
    //write:
    a[9] = new string[,] { { "echo", "foxtrot", }, { "golf", "hotel", }, { "india", "juliett", }, };
}
Run Code Online (Sandbox Code Playgroud)

[7, 8]然后我在和附近遇到各种错误的编译时错误[9],例如:

错误 CS0022 [] 内的索引数量错误;

但显然,索引计数是正确的,并且与排名一致,就像之前没有?.

数组数组和可为空引用类型的组合会完全破坏所有内容,这是一个已知的错误吗?

我相信这与线程多维数组、可空引用类型和类型转换有关。

附言!如果您在类型中以相反的顺序列出括号(用于声明参数a),它就会编译!


更新:另一个例子。如果您创建一个使用 C# 语法声明类型的成员(如字段或其他内容):

string[][,][,,][,,,][,,,,][,,,,,]  // C#
Run Code Online (Sandbox Code Playgroud)

六个括号,那么创建的 IL 具有 .NET 调用的类型:

String[,,,,,][,,,,][,,,][,,][,][]  // IL disassembly
Run Code Online (Sandbox Code Playgroud)

从 C# 1.0 和 .NET Framework 1 开始,这是正确的。但是,如果在中间放置可为 null 的标记,则在 C# 中将类型声明为:

string[][,][,,]?[,,,][,,,,][,,,,,]  // C#
Run Code Online (Sandbox Code Playgroud)

那么 IL 成员的类型为:

String[,,][,][][,,,,,][,,,,][,,,]  // IL disassembly
Run Code Online (Sandbox Code Playgroud)