C# 范围和索引方法 C#如何使用^和..操作符切片

来源:这里教程网 时间:2026-02-21 17:41:55 作者:

^
表示从末尾索引时,0 和 1 容易混淆

在 C# 8.0+ 中,

^
是“末尾索引操作符”,但它不是从 -1 开始的负数索引——
^0
指向数组末尾**之后**的位置(即等价于
Length
),
^1
才是最后一个元素。这是和 Python 负索引最常踩的坑。

arr[^1]
→ 最后一个元素(合法)
arr[^0]
→ 抛出
IndexOutOfRangeException
(因为超界)
arr[^arr.Length]
等价于
arr[0]
,但写法生硬,不推荐

实际用法中,应优先搭配范围(

..
)而非单独用
^
取单个元素,避免边界误判。

..
范围操作符的左右边界默认行为必须记清

a..b
表示从索引
a
(含)到
b
(不含)的子范围,且两个端点都支持省略或使用
^
。关键在于:省略左边界默认为
0
,省略右边界默认为
^0
(即
Length
)。

arr[..3]
→ 前 3 个元素(
[0,1,2]
arr[2..]
→ 从索引 2 到末尾(
[2, ..., Length-1]
arr[^3..]
→ 最后 3 个元素(
[Length-3, Length-2, Length-1]
arr[^3..^1]
→ 倒数第 3 个(含)到倒数第 1 个(不含),即最后 2 个元素中的前 2 个?不对:是
[Length-3, Length-2]
(共 2 个)

注意:

^1
是最后一个元素,所以
^3..^1
是「从倒数第 3 个开始,到倒数第 1 个之前」,不包含最后一个元素。

字符串、数组、Span 都支持,但 List 不直接支持

^
..
是语言级语法糖,底层依赖类型实现
Index
Range
类型,并提供对应索引器或切片方法。常见支持类型:

T[]
string
Span<t></t>
ReadOnlySpan<t></t>
:原生支持,无装箱、零分配
List<t></t>
:**不支持直接
[..]
**;需先转成数组(
list.ToArray()[1..3]
)或用
AsSpan()
list.AsSpan()[1..3]
自定义类型:需显式添加
this[Index]
this[Range]
索引器才能启用

List<t></t>
直接写
list[1..3]
会编译失败,错误信息是:
error CS0021: Cannot apply indexing with [] to an expression of type 'List<t>'</t>

性能敏感场景下,优先用
Span<t></t>
+
..
而非数组切片

数组的

[a..b]
返回的是新数组(堆分配),而
Span<t></t>
的同样操作返回的是栈上视图,无 GC 压力。这对高频解析、网络包处理等场景很关键。

string s = "hello world";
var span = s.AsSpan();         // 无复制
var sub = span[0..5];          // sub 是 Span<char>,指向原字符串内存
var arr = s.ToCharArray();     // 复制到堆
var slice = arr[0..5];         // 再次复制出新数组

如果只是临时读取、不修改,用

Span
ReadOnlySpan
配合
..
是更轻量的选择;若需后续修改或跨方法传递,再考虑转数组。

真正容易被忽略的是:

^
..
看似简单,但它们的语义依赖运行时对
Index
/
Range
的解析逻辑,一旦混用
int
Index
(比如传错参数类型),编译器可能不报错但行为异常——务必检查变量类型是否为
Index
Range
,而不是随手写个
int

相关推荐