本质论"/>
C#8.0中System.Index和System.Range的本质论
1 简介
对数组或集合的引用都要使用索引,为了进一步规范对索引的使用,从C#8.0开始,提供了两个新的只读结构体 System.Index
和 System.Range
,这两个类的具体用法官方说的很清楚:C# 8中索引和范围,故对基本概念不再细表,请直接参见官方文档。
本文的核心任务是从本质上介绍这两个类的具体内容和原理。
2 readonly struct System.Index
System.Index 是一个只读的结构体,其核心目的是用于表示集合中元素的位置。对位置的定义基本只有两种情况,即从左向右的位置和从右向左的位置。所以,Index使用以下两个属性用于索引表示:
int Value
索引的位置值;bool IsFromEnd
索引是否从尾部开始计算。
和唯一的方法GetOffset(int length)
用于计算偏移量。
// 初始化
Index id1 = new Index(1); // 等价于 new Index(1, false)
Index id2 = 1;
Index id3 = new Index(2, true);
Index id4 = ^2;
Console.WriteLine($"The last word is {words[^1]}"); // 返回 "dog"
3 应用场景示例
直到C#8.0官方才给出索引的定义目的何在呢?让我们通过下面的示例来理解。
给定一个路径 var s = @"C:\Data\Device\DCT1052"
,请提取出最后一段目录的名称,即DCT1052
,从左向右的提取方法是 s.Split('\\')[3]
。这是在路径目录深度固定的情况下,如果是不固定的就会比较麻烦,代码需要编写如下:
var dirs = s.Split('\\');
var name = dirs[dirs.Length -1 ];
这样就需要使用2行代码表示,如果非要用1行,就必需写成:
var name = s.Split('\\')[s.Split('\\').Length -1 ];
但是这样写不仅拆分做了2次,而且也不优雅。
所以,为了解决这个问题,我们只需添加一种能够从右向左表示的方法即可,而Index就是这个目的,代码可以表示如下:
var name = s.Split('\\')[new Index(1, true)];
为了进一步简单,C#引入了hat(^)运算符,new Index(1, true)
可以表示成 ^1
从而使用语句简化为 s.Split('\\')[^1];
,即:
var name = s.Split('\\')[^1]; // 对比 python更方便,可以直接使用-1
4 本质论
本质上 new Index(Value, IsFromEnd)
就是通过 IsFromEnd
指定了索引的计算方向,Value
表示偏移量,并不表示对实际数组的位置。所以,需要使用 GetOffset(length)
来计算集合长度为 length
时 索引的具体位置。当然,在从左向右数时,并不需要 length
,只有在从右向左数时才需要。但是,为了逻辑上理解的统一,我们应该将Index只表示是一种偏移量,而不是具体在指定数组中的索引。实际上,这个操作在其他语言中根本不算新鲜,比如在Python中可以通过 value[-1]的方式实现从右向左的访问。
5 System.Range
有了以上的理解,Range也容易理解,就是使用两个Index分别表示范围的 Start 和 End 的左闭右开区间,即 [Start, End)
。并可以提供了函数 (int Offset, int Length) Range.GetOffsetAndLength(length)
用于计算给定长度的区间的偏移量和长度。
示例1: (1…^1).GetOffsetAndLength(5) 表示从第1个到倒数第1个,即 [1, 4),表示从第1个表示的连续3个,与返回结果为 (1, 3) 一致;
示例2: (4…^3).GetOffsetAndLength(5) 与上面相同,但是 Start 的位置要小于 End,所以会报 Unhandled exception. System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. (Parameter 'length')
错误。
参考
[1] 微软官网, C# 8中索引和范围
[2] 微软MSDN, 从末尾运算符 ^ 开始索引
[3] CSDN文章, 关于C# 8中的Hat运算符(^)
更多推荐
C#8.0中System.Index和System.Range的本质论
发布评论