千家信息网

C#中切片语法糖怎么使用

发表于:2025-12-04 作者:千家信息网编辑
千家信息网最后更新 2025年12月04日,本篇内容主要讲解"C#中切片语法糖怎么使用",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"C#中切片语法糖怎么使用"吧!一:背景1. 讲故事昨天在 gith
千家信息网最后更新 2025年12月04日C#中切片语法糖怎么使用

本篇内容主要讲解"C#中切片语法糖怎么使用",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"C#中切片语法糖怎么使用"吧!

一:背景

1. 讲故事

昨天在 github 上准备找找 C# 9 又有哪些新语法糖可以试用,不觉在一个文档上看到一个很奇怪的写法: foreach (var item in myArray[0..5]) 哈哈,熟悉又陌生,玩过python的朋友对这个 [0..5] 太熟悉不过了,居然在 C# 中也遇到了,开心哈,看了下是 C# 8 的新语法,讽刺讽刺,8 都没玩熟就搞 9 了,我的探索欲比较强,总想看看这玩意底层是由什么支撑的。

二:.. 语法糖的用法

从前面介绍的 myArray[0..5] 语义上也能看出,这是一个切分array的操作,那到底有几种切分方式呢? 下面一个一个来介绍,为了方便演示,我先定义一个数组,代码如下:

var myarr = new string[] { "10", "20", "30", "40", "50", "60", "70", "80", "90", "100" };

1. 提取 arr 前3个元素

如果用 linq 的话,可以用 Take(3),用切片操作的话就是 [0..3], 代码如下:

static void Main(string[] args)        {            var myarr = new string[] { "10", "20", "30", "40", "50", "60", "70", "80", "90", "100" };            //1. 获取数组 前3个元素            var query1 = myarr[0..3];            var query2 = myarr.Take(3).ToList();            Console.WriteLine($"query1={string.Join(",", query1)}");            Console.WriteLine($"query2={string.Join(",", query2)}");        }

2. 提取 arr 最后三个元素

这个怎么提取呢?在 python 中直接用 -3 表示就可以了,在C# 中需要用 ^ 来表示从末尾开始,代码如下:

static void Main(string[] args)        {            var myarr = new string[] { "10", "20", "30", "40", "50", "60", "70", "80", "90", "100" };            //1. 获取数组 最后3个元素            var query1 = myarr[^3..];            var query2 = myarr.Skip(myarr.Length - 3).ToList();            Console.WriteLine($"query1={string.Join(",", query1)}");            Console.WriteLine($"query2={string.Join(",", query2)}");        }

3. 提取 array 中index = 4,5,6 的三个位置元素

用 linq 的话,就需要使用 Skip + Take 双组合,如果用切片操作的话就太简单了。。。

static void Main(string[] args)        {            var myarr = new string[] { "10", "20", "30", "40", "50", "60", "70", "80", "90", "100" };            //1. 获取数组 中 index=4,5,6 三个位置的元素            var query1 = myarr[4..7];            var query2 = myarr.Skip(4).Take(3).ToList();            Console.WriteLine($"query1={string.Join(",", query1)}");            Console.WriteLine($"query2={string.Join(",", query2)}");        }

从上面的切割区间 [4..7] 的输出结果来看,这是一个 左闭右开 的区间,所以要特别注意一下。

4. 获取 array 中倒数第三和第二个元素

从要求上来看就是获取元素 80 和 90,如果你理解了前面的两个用法,我相信这个你会很快的写出来,代码如下:

static void Main(string[] args)        {            var myarr = new string[] { "10", "20", "30", "40", "50", "60", "70", "80", "90", "100" };            //1. 获取 array 中倒数第三和第二个元素            var query1 = myarr[^3..^1];            var query2 = myarr.Skip(myarr.Length - 3).Take(2).ToList();            Console.WriteLine($"query1={string.Join(",", query1)}");            Console.WriteLine($"query2={string.Join(",", query2)}");        }

三. 探究原理

通过前面 4 个例子,我想大家都知道怎么玩了,接下来就是看看到底内部是用什么做支撑的,这里使用 DnSpy 去挖挖看。

1. 从 myarr[0..3] 看起

用 dnspy 反编译代码如下:

        //编译前    var query1 = myarr[0..3];    //编译后:        string[] query = RuntimeHelpers.GetSubArray(myarr, new Range(0, 3));

从编译后的代码可以看出,原来获取切片的 array 是调用 RuntimeHelpers.GetSubArray 得到了,然后我简化一下这个方法,代码如下:

public static T[] GetSubArray<[Nullable(2)] T>(T[] array, Range range)        {            ValueTuple offsetAndLength = range.GetOffsetAndLength(array.Length);            int item = offsetAndLength.Item1;            int item2 = offsetAndLength.Item2;            T[] array3 = new T[item2];            Buffer.Memmove(Unsafe.As(array3.GetRawSzArrayData()), Unsafe.Add(Unsafe.As(array.GetRawSzArrayData()), item), (ulong)item2);            return array3;        }

从上面代码可以看到,最后的 子array 是由 Buffer.Memmove 完成的,但是给 子array 的切割位置是由 GetOffsetAndLength 方法实现,继续追一下代码:

     public readonly struct Range : IEquatable    {           public Index Start { get; }        public Index End { get; }                public Range(Index start, Index end)                {                        this.Start = start;                        this.End = end;                }        public ValueTuple 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(num, num2 - num);        }    }

看完上面的代码,你可能有两点疑惑:

1) start.IsFromEnd 和 end.IsFromEnd 是什么意思。

其实看完上面代码逻辑,你就明白了,IsFromEnd 表示起始点是从左开始还是从右边开始,就这么简单。

2) 我并没有看到 start.IsFromEnd 和 end.IsFromEnd 是怎么赋上值的。

在 Index 类的构造函数中,取决于上一层怎么去 new Index 的时候塞入的 true 或者 false,如下代码:

这个例子的流程大概是: new Range(1,3) -> operator Index(int value) -> FromStart(value) -> new Index(value) ,可以看到最后在 new 的时候并没有对可选参数赋值。

2. 探究 myarr[^3..]

刚才的例子是没有对可选参数赋值,那看看本例是不是 new Index 的时候赋值了?

//编译前:var query1 = myarr[^3..];//编译后:string[] query = RuntimeHelpers.GetSubArray(myarr, Range.StartAt(new Index(3, true)));

看到没有,这一次 new Index 的时候,给了 IsFromEnd = true , 表示从末尾开始计算,大家再结合刚才的 GetOffsetAndLength 方法,我想这逻辑你应该理顺了吧。

到此,相信大家对"C#中切片语法糖怎么使用"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

代码 元素 C# 语法 编译 数组 方法 时候 三个 位置 例子 就是 是由 内容 区间 参数 朋友 末尾 这是 逻辑 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 班级网络安全责任 电脑怎么查询服务器端口 网络安全方案策略 智付软件开发 武汉大学国家网络安全学院大门 数据库新建后边加什么字母 网络信号提示无法连接服务器 服务器网卡和交换机哪个好 财经学校计算机网络技术 eclipse数据库管理 网络技术Ap 六安oa管理软件开发费用 计算机网络技术与应用应用题 华硕云存储服务器怎么样 无法连接至逃脱者服务器 安全狗可以加服务器吗 生产数据库能不能去修改数据 达州软件开发哪家不错 做完表格如何再创建数据库 邯郸工控软件开发价格表 数据库 表 数据是什么关系 政府采软件开发采购项目 福建服务器维修维保虚拟主机 武汉市网络安全技术支撑 需要紧急连接网络访问公司服务器 人工智能应用软件开发问答知识 淘宝租服务器自己这边需要联网吗 现在主流的数据库管理系统 条码打印机用什么软件开发 联宝服务器测试调试
0