C# Linq源码分析之Take (一)

概要

在.Net 6 中引入的Take的另一个重载方法,一个基于Range的重载方法。因为该方法中涉及了很多新的概念,所以在分析源码之前,先将这些概念搞清楚。

Take方法基本介绍

public static System.Collections.Generic.IEnumerable Take (this System.Collections.Generic.IEnumerable source, Range range);

新的Take重载方法不再接收整数参数,而是接收一个Range类型的参数。它可以从序列中返回指定范围的连续元素。

注意:该方法只能在.Net 6 或更高版本中使用,我们之前用的.Net 4.7, 4.8或.Net Core 3.1中,都不支持该方法。

Range参数的数据结构

Take重载方法的参数是Range类型,Range本身是一个struct, 表示具有起始索引和结束索引的范围。

Range有两个重要的属性Start和End,表示Range的启始索引值和结束索引值,在Take 方法中只会取到结束索引值的前一个元素。

End和Start的属性的类型值是Index,也是struct结构。包含两个重要属性,Value和IsFromEnd。

IsFromEnd是bool类型,表示是正数还是倒数,例如我们可以写成3...^1 表示从第三个到倒数第一个。

Value是int类型,表示索引值。无论是1 或^1, 索引值都是1。

Take 方法的基本使用

csharp 复制代码
static void Main(string[] args)
{
    Range range = 1..3;
    List<string> list = new List<string> { "A", "B", "C", "D", "E", "F", "G" };
    foreach(var val in list.Take(range))
    {
        Console.WriteLine(val);
    }
}

输出结果是 B 和 C

C#中对Range的定义与Python类似。

C#中可以按照正数的方式设定Range,也可以按照倒数的方式设定,也可以按照正数和倒数的混合方式设定Range。

上述代码中,我们将Range定义为Range range = ^6...3;,也可以得到相同的结果。

但是需要注意的是,Take方法中的Range必须是有意义的,注意下面的情况:

  • ^1...3, 代人Take将得到空序列,因为无论正数还是倒数,Range的开始值必须小于结尾的值, 在上面例子中 ^1就是6,相当于去从第6个到第3个元素,显然是不合理的,结果为空。
  • 3...^4, 代人Take将得到空序列,该Range等价于取从第3个到第3个元素,结果是空。
  • 无论正数还是倒数,都可以越界,我们写成0...100或 ^100... ^1,都能拿到序列的全部元素,不会抛出越界异常。

Take中使用TryGetNonEnumeratedCount方法实现优化

TryGetNonEnumeratedCount方法的基本定义如下:

public static bool TryGetNonEnumeratedCount (this System.Collections.Generic.IEnumerable source, out int count);

该方法用于在不遍历序列元素的情况的下,获取序列中元素个数。

如果目标序列source实现了 ICollection接口,则需要实现Count属性。因此该函数可以直接获取Count属值,并返回True,输出参数count是序列中的元素个数。

如果目标序列source没有实现ICollection接口,则无法直接获取元素个数,因此该函数返回False,count是0。

Take 在执行过程中,如果我们的Range值设定的是倒数方式,我们就需要知道序列中元素的个数,然后将倒数值变成正数值,最后后按照索引取值。

试想如果目标序列数据量很大,如果可以直接获取序列中元素的个数,就可以避免逐个元数遍历,再获取序列中元素个数,可以实现优化,提高代码运行速度。

相关推荐
ahhhhaaaa-5 分钟前
【AI图像生成网站&Golang】部署图像生成服务(阿里云ACK+GPU实例)
开发语言·数据仓库·人工智能·后端·阿里云·golang
一只编程菜鸟11 分钟前
Java + easyexcel 新旧数据对比,单元格值标红
java·开发语言
WineMonk1 小时前
ArcPy 与 ArcGIS .NET SDK 读取 GDB 要素类坐标系失败?GDAL 外挂方案详解
arcgis·c#·.net·arcgispro
界面开发小八哥1 小时前
界面开发框架DevExpress XAF实践:集成.NET Aspire后如何实现服务安排?
c#·.net·界面控件·devexpress·ui开发·xaf
fs哆哆1 小时前
在VB.net中,用正则表达式方法清除干扰符号方法
开发语言·正则表达式·c#·.net
嵌入式@秋刀鱼1 小时前
《 第三章-招式初成》 C++修炼生涯笔记(基础篇)程序流程结构
linux·开发语言·数据结构·c++·笔记·visual studio code
shenyan~1 小时前
关于 WASM: WASM + JS 混合逆向流程
开发语言·javascript·wasm
梦境虽美,却不长2 小时前
C语言 学习 文件操作(开关,读写,定位,大小)操作 2025年6月8日12:19:24
c语言·开发语言·学习
Charlotte_jc2 小时前
完美解决openpyxl保存Excel丢失图像/形状资源的技术方案
开发语言·python·excel·openpyxl
西北大程序猿2 小时前
服务器代码知识点补充
服务器·开发语言·网络·c++·网络协议