📍 索引与范围速查 Indices & Ranges

C# 8 引入 · ^ 末尾索引 · .. 范围切片 · 📖 完整课程

末尾索引Index from End^

核心公式:^n = Length - n。这不是随意定的——是为了让范围(Ranges)的数学性质干净。
int[] arr = [10, 20, 30, 40, 50];  // Length = 5

// ^ 映射表
^0 → 5 - 0 = 5   // 等于 Length——"末尾之后"的位置
^1 → 5 - 1 = 4   // 最后一个元素(值 50)
^2 → 5 - 2 = 3   // 倒数第二个(值 40)
^5 → 5 - 5 = 0   // 第一个元素(值 10)

// 使用
var last = arr[^1];        // 50
var secondLast = arr[^2];  // 40

// Index 是独立类型
Index i1 = ^1;   // 倒数第一
Index i2 = 0;    // 正向索引
^0 不是最后一个元素!它是 Length——"末尾之后"。取最后一个元素用 ^1
这和正向索引一致:正向 0 是"开头",负向 ^0 是"结尾之后"——对称。

范围Range..

左闭右开:[start..end)——包含 start,不包含 end。这和 Span<T>.Slice 的语义一致。
int[] arr = [0, 1, 2, 3, 4, 5];  // 索引: 0  1  2  3  4  5

// 基本用法
arr[0..3]    → [0, 1, 2]       // 从开头取 3 个
arr[^3..^1]  → [3, 4]          // 倒数第3 到 倒数第1(不含)
arr[^3..^0]  → [3, 4, 5]       // 最后 3 个——^0 是 Length

// 省略语法
arr[3..]     → [3, 4, 5]       // 省略右端 = 到末尾
arr[..3]     → [0, 1, 2]       // 省略左端 = 从头开始
arr[..]      → [0, 1, 2, 3, 4, 5] // 两端省略 = 全取

// ^ 省略组合
arr[^3..]    → [3, 4, 5]       // 省略右端 = 等价于 [^3..^0]
arr[..^1]    → [0, 1, 2, 3, 4] // 去掉最后一个

Range 速查表(arr = [0,1,2,3,4,5],Length=6)

写法等价 [start..end)结果说明
arr[0..3][0..3)[0,1,2]前 3 个
arr[3..6][3..6)[3,4,5]索引 3 到末尾
arr[^3..^0][3..6)[3,4,5]最后 3 个
arr[^3..][3..6)[3,4,5]等价于上
arr[..^1][0..5)[0,1,2,3,4]去掉最后一个
arr[^2..^1][4..5)[4]倒数第二个单元素
arr[..][0..6)全部浅拷贝

支持的类型

任何有 Count/Length 属性 + int 索引器 + Slice(int, int) 方法的类型:

类型示例
T[]int[], string[]
stringstr[1..^1] — 去掉首尾字符,返回 string
Span<T> / ReadOnlySpan<T>"Hello".AsSpan()[0..5]
Memory<T> / ReadOnlyMemory<T>同 Span,堆上版本
List<T>需通过 CollectionsMarshal.AsSpan(list)[..]

Using 声明Using Declaration (C# 8)

Using 语句(旧)

using (var conn = OpenConn())
using (var cmd = conn.CreateCmd())
{
    // conn 和 cmd 在 } 时释放
}

Using 声明(新)

using var conn = OpenConn();
using var cmd = conn.CreateCmd();
// 离开作用域时释放(通常方法结束)
Using 语句Using 声明 (C# 8)
写法using (var x = ...) { }using var x = ...;
释放时机} 时立即释放变量离开作用域时释放
有自己的作用域否(变量属于父作用域)
Using 声明在变量离开作用域时才释放(通常是方法结束)。如果资源需要尽早释放(如在重计算之前),仍需用老式 using 语句。

相关速查