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)