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值设定的是倒数方式,我们就需要知道序列中元素的个数,然后将倒数值变成正数值,最后后按照索引取值。

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

相关推荐
迪丽热爱7 小时前
一、C语言概述与程序结构
c语言·开发语言·算法
HUIBUR科技7 小时前
AI中枢:打破数据孤岛与流程孤岛双重困境
开发语言·ai
胖纸不争7 小时前
嫌桌面 Agent 太重,我“自己”写了一个
ai·c#·net core
鱼宵7 小时前
LangChain4j 结构化输出:让模型吐出 Java 对象,JSON 不再手写解析
java·开发语言·json·langchain4j
w2sfot7 小时前
【JS加密在线】jsjiami.online(让JavaScript 更安全!)
开发语言·javascript·安全
Wang's Blog8 小时前
Java 项目部署之 Docker工具快速入门: Docker 是什么以及它如何解决部署环境问题
java·开发语言·docker
老木避暑研究所8 小时前
从原始数据到洞察:一次完整的避暑房环境数据采集、清洗与可视化分析
java·开发语言
程序喵大人8 小时前
【C++入门】编译链接模型 - 05 ODR 为什么会让重复定义变成工程炸点
开发语言·c++·编译链接·odr
weixin199701080168 小时前
《淘宝TOP API:落地方案、接口边界与业务踩坑 —— 聚石塔内外价差 10 倍的真相》(附 Python 源码)
开发语言·python