C# 中居然也有切片语法糖,太厉害了

有没有人在啊,想请教一下,C# 中居然也有切片语法糖,太厉害了
最新回答
元嘉草草

2026-10-25 10:33:29

C# 8.0 引入的切片语法糖(..)确实是一个非常实用的功能,它允许开发者以简洁的方式对数组、字符串等类型进行切片操作。以下是对该功能的详细解析:

一、切片语法糖的基本用法1. 提取前N个元素var myarr = new string[] { "10", "20", "30", "40", "50", "60", "70", "80", "90", "100" };var query1 = myarr[0..3]; // 提取前3个元素
  • 效果:query1 包含 "10", "20", "30"。
  • 对比 LINQ:等价于 myarr.Take(3).ToList()。
2. 提取最后N个元素var query1 = myarr[^3..]; // 提取最后3个元素
  • 效果:query1 包含 "80", "90", "100"。
  • 关键符号:^ 表示从末尾开始计算索引。
  • 对比 LINQ:等价于 myarr.Skip(myarr.Length - 3).ToList()。
3. 提取指定范围的元素var query1 = myarr[4..7]; // 提取索引4到6的元素(左闭右开)
  • 效果:query1 包含 "50", "60", "70"。
  • 注意:区间是左闭右开的,即包含起始索引,不包含结束索引。
4. 提取倒数第N到倒数第M个元素var query1 = myarr[^3..^1]; // 提取倒数第3到倒数第2个元素
  • 效果:query1 包含 "80", "90"。
二、切片语法糖的原理1. 编译后的代码

切片操作在编译后会被转换为对 RuntimeHelpers.GetSubArray<T> 方法的调用:

// 编译前var query1 = myarr[0..3];// 编译后string[] query = RuntimeHelpers.GetSubArray<string>(myarr, new Range(0, 3));2. Range 和 Index 类型
  • Range 结构:表示一个范围,包含 Start 和 End 两个 Index 属性。public readonly struct Range{ public Index Start { get; } public Index End { get; } public Range(Index start, Index end) { this.Start = start; this.End = end; }}
  • Index 结构:表示一个索引,可以是正向或反向的。public readonly struct Index{ private readonly int _value; private readonly bool _fromEnd; public int Value => _value; public bool IsFromEnd => _fromEnd; public Index(int value, bool fromEnd = false) { _value = value; _fromEnd = fromEnd; }}
3. GetOffsetAndLength 方法

该方法用于计算切片的起始位置和长度:

public ValueTuple<int, int> GetOffsetAndLength(int length){ Index start = this.Start; int num; if (start.IsFromEnd) { num = length - start.Value; } else { num = start.Value; } Index end = this.End; int num2; if (end.IsFromEnd) { num2 = length - end.Value; } else { num2 = end.Value; } return new ValueTuple<int, int>(num, num2 - num);}
  • 逻辑:

    如果 Start 或 End 是反向索引(IsFromEnd = true),则从数组末尾开始计算。

    返回的元组包含切片的起始位置和长度。

4. 内存拷贝

最终的切片操作是通过 Buffer.Memmove 方法完成的,该方法高效地拷贝内存中的数据:

public static T[] GetSubArray<T>(T[] array, Range range){ ValueTuple<int, int> offsetAndLength = range.GetOffsetAndLength(array.Length); int item = offsetAndLength.Item1; int item2 = offsetAndLength.Item2; T[] array3 = new T[item2]; Buffer.Memmove<T>(Unsafe.As<byte, T>(array3.GetRawSzArrayData()), Unsafe.Add<T>(Unsafe.As<byte, T>(array.GetRawSzArrayData()), item), (ulong)item2); return array3;}三、切片语法糖的优势1. 简洁性
  • 切片语法糖比传统的 Skip 和 Take 组合更简洁,代码更易读。
  • 例如,提取前3个元素:var query1 = myarr[0..3]; // 切片语法糖var query2 = myarr.Take(3).ToList(); // LINQ
2. 性能
  • 切片操作在底层是通过高效的内存拷贝实现的,性能优于 Skip 和 Take 的组合。
3. 适用性
  • 切片语法糖不仅适用于数组,还适用于字符串:var str = "12345";var subStr = str[1..3]; // 结果为 "23"

    等价于 str.Substring(1, 2)。

四、总结

C# 8.0 引入的切片语法糖(..)是一个强大的功能,它通过简洁的语法和高效的底层实现,极大地简化了数组和字符串的切片操作。无论是提取前N个元素、最后N个元素,还是指定范围的元素,切片语法糖都能以直观的方式完成任务。此外,它还减少了代码量,提高了可读性和性能。对于熟悉 Python 的开发者来说,这一语法糖无疑是一个亲切的惊喜。