C# 试题 20:数组、Index 与 Range
0381 以下代码运行结果是什么?
难度: 实战
object[] items = new string[3];
items[0] = 1;
- A. 正常运行,
1被装箱写入数组 - B. 运行抛
ArrayTypeMismatchException - C. 编译失败,
object[]与string[]不能互相赋值 - D. 运行抛
InvalidCastException
查看答案与解析
正确答案B
解析: 数组协变允许把 string[] 的引用赋给 object[],但底层数组的元素类型仍是 string;写入不兼容类型时运行期检查失败,抛 ArrayTypeMismatchException。
关键点: 协变只放宽“读取”,写入仍受实际元素类型约束。
0382 以下代码能否编译?
难度: 进阶
object[] items = new int[3];
- A. 编译失败,值类型数组不参与协变
- B. 编译通过,
int[]可隐式转换为object[] - C. 编译通过,但运行抛
ArrayTypeMismatchException - D. 编译通过,且运行正常
查看答案与解析
正确答案A
解析: 数组协变只适用于引用类型;int[] 到 object[] 不存在隐式转换,赋值在编译期就被拒绝。
关键点: “所有数组都能转 object[]”是常见误读,值类型数组除外。
0383 以下代码输出什么?
难度: 实战
int[,] rect = new int[2, 3];
int[][] jag = new int[3][];
jag[0] = new int[1];
jag[1] = new int[2];
jag[2] = new int[3];
Console.WriteLine(rect.Rank + " " + rect.Length + " " + jag.Length);
- A.
3 6 3 - B.
2 6 6 - C.
2 9 3 - D.
2 6 3
查看答案与解析
正确答案D
解析: rect.Rank 为 2;rect.Length 是元素总数 2 × 3 = 6。jag 本身是一维数组,Length 是子数组个数 3。
关键点: 多维数组的 Length 是全部元素数而不是行数,GetLength(i) 才取某一维的长度。
0384 以下代码运行结果是什么?
难度: 实战
int[][] jag = new int[3][];
Console.WriteLine(jag[0][0]);
- A. 输出
0 - B. 编译失败
- C. 运行抛
NullReferenceException - D. 运行抛
IndexOutOfRangeException
查看答案与解析
正确答案C
解析: new int[3][] 只创建外层数组,三个子数组都是 null;访问 jag[0][0] 先对 null 子数组解引用,抛 NullReferenceException。
关键点: 交错数组的子数组不会自动初始化。
0385 以下代码输出什么?
难度: 实战
int[] a = { 10, 20, 30, 40 };
Console.WriteLine(a[^1]);
Console.WriteLine(a[^4]);
- A.
40和0 - B.
40和10 - C.
30和10 - D. 运行抛
IndexOutOfRangeException
查看答案与解析
正确答案B
解析: ^n 表示“从末尾数第 n 个”,等价于 Length - n:^1 是 a[3] 即 40,^4 是 a[0] 即 10。
关键点: ^n 的语义是 Length - n,不要记成“倒数第 n+1 个”。
0386 以下代码运行结果是什么?
难度: 进阶
int[] a = { 1, 2, 3 };
Console.WriteLine(a[^0]);
- A. 输出
3 - B. 输出
0 - C. 编译失败
- D. 运行抛
IndexOutOfRangeException
查看答案与解析
正确答案D
解析: ^0 计算为 Length - 0 = 3,超出最后一个索引,等价于访问 a[3],抛 IndexOutOfRangeException。
关键点: ^0 指向“长度位置”而不是“最后一个元素”,是最常见的 Index 陷阱。
0387 以下代码运行结果是什么?
难度: 实战
int[] a = { 1, 2 };
Console.WriteLine(a[^3]);
- A. 运行抛
IndexOutOfRangeException - B. 输出
1 - C. 输出
0 - D. 运行抛
ArgumentOutOfRangeException
查看答案与解析
正确答案A
解析: ^3 计算为 2 - 3 = -1,负索引非法,抛 IndexOutOfRangeException,而不是 ArgumentOutOfRangeException。
关键点: ^n 中 n 大于数组长度时越界,异常类型是 IndexOutOfRangeException。
0388 以下代码输出什么?
难度: 实战
int[] a = { 1, 2, 3, 4, 5 };
int[] b = a[1..4];
b[0] = 99;
Console.WriteLine(string.Join(",", a));
- A.
99,2,3,4,5 - B.
1,99,3,4,5 - C.
1,2,3,4,5 - D.
1,2,3,99,5
查看答案与解析
正确答案C
解析: 对数组做 Range 切片会复制出全新数组,b 与原数组不共享存储;修改 b[0] 不影响 a。
关键点: 数组的 [1..4] 是拷贝语义;只有 Span/ReadOnlySpan 的切片才是共享视图。
0389 以下代码输出什么?
难度: 实战
int[] a = { 0, 1, 2, 3, 4 };
Console.WriteLine(string.Join(",", a[^3..^1]));
- A.
1,2,3 - B.
3,4 - C.
2,3,4 - D.
2,3
查看答案与解析
正确答案D
解析: ^3..^1 展开为 (5-3)..(5-1) 即 2..4,包含索引 2、3,对应元素 2,3;Range 终点是开区间。
关键点: Range 的终点开区间,^n 在起点和终点都按 Length - n 计算。
0390 以下代码运行结果是什么?
难度: 进阶
int[] a = { 1, 2, 3, 4, 5 };
Console.WriteLine(a[3..1].Length);
- A. 运行抛
ArgumentOutOfRangeException - B. 输出
0(空切片) - C. 输出
2 - D. 输出
3
查看答案与解析
正确答案A
解析: Range 要求起点不超过终点;3..1 起点大于终点,数组切片直接抛 ArgumentOutOfRangeException,不会返回空数组或倒序结果。
关键点: a[3..3] 才是空切片,起点大于终点是异常。
0391 以下代码输出什么?
难度: 进阶
int[] a = { 1, 2, 3, 4, 5 };
Console.WriteLine(a[..^0].Length);
Console.WriteLine(a[^0..].Length);
- A.
0和5 - B.
5和0 - C.
5和5 - D. 第一行抛
IndexOutOfRangeException
查看答案与解析
正确答案B
解析: ..^0 的终点是 Length - 0 = 5,取到完整数组;^0.. 的起点是 5,得到空切片。作为 Range 的终点,^0 合法;只有把它当单个索引 a[^0] 才会越界。
关键点: 同样的 ^0,放在 Range 终点与放在方括号索引里语义不同。
0392 关于 System.Index 与 ^ 语法,哪项正确?
难度: 进阶
- A.
^1对任何数组都等价于Length - 1,空数组也安全 - B.
Index是 ref struct,不能装箱也不能作为字段 - C.
Index是普通 readonly struct:^n的IsFromEnd为 true,且支持从int隐式转换 - D.
^0与0语义完全相同
查看答案与解析
正确答案C
解析: Index 是 readonly struct,^n 等价于 new Index(n, fromEnd: true);int 可隐式转换为 Index。空数组上 ^1 会越界;^0 与 0 在方括号索引中一个越界、一个取首元素,语义不同。
关键点: Index 只是“偏移量 + 方向”的描述,安全与否取决于容器长度。
0393 以下代码输出什么?
难度: 实战
var pool = ArrayPool<int>.Shared;
int[] buf = pool.Rent(10);
Console.WriteLine(buf.Length >= 10);
pool.Return(buf);
- A.
False - B. 运行抛
ArgumentException - C. 编译失败,使用
ArrayPool需要unsafe - D.
True,Rent返回的数组长度可能大于请求值
查看答案与解析
正确答案D
解析: 默认池按 2 的幂分桶,Rent(10) 落在容量 16 的桶里,返回长度 16 的数组;契约只保证“不小于请求值”,调用方应只使用前 10 个元素。
关键点: 不要把租借数组的 Length 当成请求值。
0394 以下代码输出什么?
难度: 实战
var pool = ArrayPool<int>.Shared;
int[] buf = pool.Rent(0);
Console.WriteLine(buf.Length);
pool.Return(buf);
- A. 输出
0 - B. 输出
16 - C. 输出
128 - D. 运行抛
ArgumentOutOfRangeException
查看答案与解析
正确答案A
解析: Rent(0) 被当作合法请求特殊处理,直接返回空数组(长度 0),不会落入最小桶 16。
关键点: 最小桶大小只约束正请求,Rent(0) 不占任何桶。
0395 关于 ArrayPool 的“归还后不得继续使用”契约,哪项正确?
难度: 进阶
- A.
Return后数组内容会被自动清零,可以继续安全读取 - B. 归还后不得再访问该数组:池可能已把它复用于其他租借请求,继续读写会破坏数据
- C.
Return必须在Rent后一秒钟内调用,否则抛异常 - D.
Rent返回的数组长度必然等于请求值
查看答案与解析
正确答案B
解析: Return 只是把数组交回池中,之后数组不再属于调用方;同一数组可能立刻被下一次 Rent 复用,继续使用属于未定义行为。
关键点: ArrayPool 的生命周期契约是“借出期间独占,归还即失效”。
0396 以下代码哪项说法正确?
难度: 实战
var pool = ArrayPool<string>.Shared;
string[] buf = pool.Rent(8);
buf[0] = "secret";
pool.Return(buf); // 未传 clearArray: true
- A.
Return时数组内容会被自动清零 - B. 数组被立即释放,之后无法被其他代码读取
- C. 数组留在池中且内容保持不变;处理敏感数据时应传
clearArray: true或归还前自行清理 - D. 编译失败,
ArrayPool<string>不存在
查看答案与解析
正确答案C
解析: Return 的 clearArray 参数默认是 false,不会清零元素;下一次 Rent 可能拿到这份残留数据。敏感数据必须显式清理。
关键点: 默认归还不清零,池是共享的,“别人可能读到你的数据”。
0397 以下模式哪项说法正确?
难度: 进阶
var pool = ArrayPool<int>.Shared;
int[] buf = pool.Rent(64);
try
{
// 使用 buf 处理数据
}
finally
{
pool.Return(buf);
}
- A.
finally中应再次调用Rent - B.
try/finally多余,可以直接Return - C.
Return必须放在try块内 - D. 正确:即使处理过程抛异常,
finally也保证归还,避免长期占用池中数组
查看答案与解析
正确答案D
解析: finally 保证正常路径与异常路径都执行归还;不归还会造成池中的数组被长期占用,甚至迫使池扩容。这是使用 ArrayPool 的标准姿势。
关键点: 借多少还多少,异常路径也要还。
0398 关于 int[,] 与 int[][],哪项正确?
难度: 进阶
- A.
int[,].Length返回元素总数(行 × 列),int[][]的每个子数组长度可以不同 - B.
int[,].Length返回行数 - C.
int[,]与int[][]可以互相隐式转换 - D.
int[,]支持数组协变
查看答案与解析
正确答案A
解析: 多维数组是“一整块”矩形存储,Length 为全部元素数;交错数组是“数组的数组”,各子数组长度自由。两者类型不同、不能互转;值类型数组不参与协变。
关键点: 矩形与交错是两种布局,Length 的语义也不同。
0399 以下代码输出什么?
难度: 进阶
int[] a = { 1, 2, 3, 4, 5 };
Range r = 1..^1;
Console.WriteLine(string.Join(",", a[r]));
- A.
2,3 - B.
2,3,4 - C.
1,2,3,4 - D.
1,2,3,4,5
查看答案与解析
正确答案B
解析: Range 是结构体,1..^1 展开为 1..4,取索引 1、2、3,即 2,3,4;终点开区间。
关键点: Range 可以存成变量复用,起止语义与切片表达式一致。
0400 以下代码输出什么?
难度: 实战
var pool = ArrayPool<byte>.Shared;
byte[] buf = pool.Rent(1_500_000);
Console.WriteLine(buf.Length);
pool.Return(buf);
- A.
1500000 - B.
1048576 - C.
2097152 - D. 运行抛
OutOfMemoryException
查看答案与解析
正确答案C
解析: 默认池按 2 的幂取桶,1_500_000 向上取整到 2^21 = 2_097_152;只要请求小于桶上限,就会得到整桶大小的数组。
关键点: 租借长度是“不小于请求的最小 2 的幂”,大请求同样可能偏大。