C# 的范围(
..)和索引(
^)操作符是 C# 8.0 引入的语法糖,让数组、字符串、Span 等支持索引的类型更简洁地表达“取某一段”或“从末尾数第几个”,不用再手动算长度。
用 ^
表示从末尾开始的索引
^n等价于
length - n,其中
n是正整数。它不是负数索引,而是一个独立的索引类型
System.Index。
array[^1]取最后一个元素,等价于
array[array.Length - 1]
array[^3]取倒数第三个,等价于
array[array.Length - 3]
^0是合法的,但对应的是
length - 0,即越界位置(常用于范围的右边界)
用 ..
表示范围(Range)
start..end创建一个
System.Range,表示从
start(含)到
end(不含)之间的子序列。start 和 end 都可以是
int或
Index。
str[2..5]取下标 2、3、4 的字符(共 3 个)
arr[..3]取前 3 个元素(等价于
0..3)
arr[3..]取从下标 3 到末尾(等价于
3..arr.Length)
arr[^3..^1]取倒数第 3 个(含)到倒数第 1 个(不含),也就是倒数第 3 和第 2 个
底层其实是 Range
和 Index
类型
编译器会把
^n转成
new Index(n, fromEnd: true),把
a..b转成
new Range(new Index(a), new Index(b))。目标类型必须提供接受
Range的索引器(如
string.this[Range]或
T[] this[Range])才能使用。 内置支持的类型包括:数组(
T[])、
string、
Span<t></t>、
ReadOnlySpan<t></t>自定义类型要支持,需定义形如
public T[] this[Range range] => ...的索引器 注意:
Range本身不执行越界检查,实际切片时由目标类型的索引器负责校验
常见误区和注意事项
这些操作看着简单,但容易踩坑:
^0不是最后一个元素,而是“长度位置”,用作范围右边界时才自然(如
[2..^0]表示从 2 到末尾)
arr[^5..^2]要求数组长度 ≥ 5;如果长度只有 3,
^5就会抛
IndexOutOfRangeException范围不支持反向(如
5..2),也不支持步长(不能写
[..^1 by 2])——那是 LINQ 的事 字符串使用范围返回的是新字符串(不可变),不是视图;而
Span返回的是原内存的只读视图
基本上就这些。写起来清爽,读起来直观,只要记住
^n是“倒数第 n 个”,
..是“左闭右开”,再配合类型是否真正支持,就很少出错。
