重学c#系列——linq(1) [二十七]
前言
简单介绍一下linq,linq很多人其实用的很熟练了,但是有些人不知道自己用的是linq。
正文
在介绍linq 之前,先介绍一下集合。
public interface ICollection<T> : IEnumerable<T>, IEnumerable
{
int Count { get; }
bool IsReadOnly { get; }
void Add(T item);
void Clear();
bool Contains(T item);
void CopyTo(T[] array, int arrayIndex);
bool Remove(T item);
}
什么是集合呢?在c# 中拥有上面功能的就是集合。
这里面可以看到集合继承了IEnumerable 这个接口。
继承这个接口意味集合可以列举的,也就是简单来说可以遍历的。
那么c# 中的集合是否一定要继承ICollection。
这个就不一定,比如说字典,字典在现实生活中明显是一组集合吧,那么在c# 中也应该是即可。

为什么字典不继承ICollection,原因也很简单,因为void Add(T item); 对字典来说没有意义。
字典是key 和 value 这种模式,ICollection 是无法满足很多集合需求的,因为集合的多样性太多了(非常丰富)。
那么在c# 中什么样的是集合呢? 继承IEnumerable的就是集合。
如果要数据初始化的话,那么要增加Add方法。
public class TestCollection<T> : IEnumerable<T>
{
public void Add(T a)
{
}
public void Add(List<T> a)
{
}
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
这里有两个add,一个增加T,一个增加T列表。
internal class Program
{
static void Main(string[] args)
{
List<string> l = new List<string>() { "1", "2", "3"};
TestCollection<string> a = new TestCollection<string>()
{
"123",
l
};
}
}
这样就ok了。
我们知道实现了Ienumerable的可以进行遍历。
因为IEnumerable 返回了一个 IEnumerator GetEnumerator();。

迭代器就是while,然后MoveNext,然后再Current,获取数据。

这里有些人可能会有一个很小的问题,那就是为什么不直接实现迭代器,而是有一个IEnumerable,里面有一个IEnumerator GetEnumerator();。
原因很简单,因为遍历每次都是从头开始,都是一个新的开始。
因为IEnumerator 继承 IDisposable, 如果需要每次遍历完做某些事情的话,可以放在IEnumerator的void Dispose();中实现。
所以foreach 实际上是干了这样一件事。

那么foreach 是否一定要继承IEnumerable 呢? 这个不一定。
foreach 采用一个duck typing的这种方式,duck typing是什么意思呢?就是走起来想一只鸭子,然后叫起来像一只鸭子,那么就是鸭子。
只要有GetEnumerator就行:
internal class Program
{
static void Main(string[] args)
{
List<string> l = new List<string>() { "1", "2", "3"};
TestForeach<string> a = new TestForeach<string>();
foreach (var b in a)
{
}
}
}
public class TestForeach<T>
{
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
}
在foreach 循环中不能进行赋值。

同样在foreach 循环中不能对集合的个数进行修改。

无论是增加还是删除list的version都会发生变化。
很多书里面介绍了,为什么不能复制和增加集合个数,这样会使人头脑不清醒。
因为这是遍历,应该是一个原子,这样的设计不会添加歧义性,单一职责逻辑清晰能减少不必要的bug。
一般来说都会继承一下IEnumerable 这个接口。 为什么呢?因为linq。
linq 是 language integated query,语言集成查询。
也就是说定义了一套规范哈,对于我们来说其实不用太在意这个规范是什么,大体看一下就行。
对IEnumerable而言,实现的就在system.IEnumberable.linq 上面,引用用就好。
然后linq有一个很大的特点,就是延迟执行。
然后来说下这个延迟执行是怎么实现的哈。
比如我们的list 经过where 之后,其实在运行时就不是linq。
运行时是这个类型WhereListIterator。

就看个list的。

执行where 其实就是把list 给 WhereListIterator。

并没有生成新的list,所以说不会执行where操作。
当遍历的时候就会执行WhereListIterator的movenext。

遍历的时候就会做条件判断。
所以呢,如果进行多次遍历后呢,其实一直都在执行你的where 语句。
如果需要遍历多次,where 循环后,最好直接tolist转换成一个list。
当然有兴趣可以去看下其他的,这里只是举个例子,其实就是用包装器模式实现的。
这样经过层层包装,人们就会想啊,如果where 语句按照顺序执行,那么不会很慢啊。
所以linq还可以并行实现,使用asParallel(),这个东西来实现。

这样运行就是并行的, 先不管实现,并行篇会介绍,只需要知道官方帮我们实现了,这样运行更快就可以了。
结
因为东西比较多,下一节是一些复杂的linq和匿名linq,下下节是查询表达式。 linq 是实现其实很复杂,但是用起来是真的简单。
重学c#系列——linq(1) [二十七]的更多相关文章
- 重学c#系列——list(十二)
前言 简单介绍一下list. 正文 这里以list为介绍. private static readonly T[] s_emptyArray = new T[0]; public List() { t ...
- 重学c#系列——字典(十一)
前言 重学c#系列继续更新,简单看一下字典的源码. 看源码主要是解释一下江湖中的两个传言: 字典foreach 顺序是字典添加的顺序 字典删除元素后,字典顺序将会改变 正文 那么就从实例化开始看起,这 ...
- 重学c#系列——对c#粗浅的认识(一)
前言 什么是c#呢? 首先你是如何读c#的呢?c sharp?或者c 井? 官方读法是:see sharp. 有没有发现开发多年,然后感觉名字不对. tip:为个人重新整理,如学习还是看官网,c# 文 ...
- 重学c#系列——datetime 和 datetimeoffset[二十一]
前言 简单介绍一下datetime和 datetimeoffset. 正文 了解一个国家的文化,就要了解一个国家的历史. 要了解datetimeoffset,那么很有必要了解一下datetime. 表 ...
- 重学c#系列——c#运行原理(二)
前言 c# 是怎么运行的呢?是否和java一样运行在像jvm的虚拟机上呢?其实差不多,但是更广泛. c# 运行环境不仅c#可以运行,符合.net framework 开发规范的都可以运行. c# 程序 ...
- 重学c#系列——string.empty 和 "" 还有null[二十]
前言 简单整理一下string.empty 和 "" 还有 null的区别. 正文 首先null 和 string.empty 还有 "" 是不一样的. nul ...
- 重学Golang系列(一): 深入理解 interface和reflect
前言 interface(即接口),是Go语言中一个重要的概念和知识点,而功能强大的reflect正是基于interface.本文即是对Go语言中的interface和reflect基础概念和用法的一 ...
- 重学c#系列——c# 托管和非托管资源(三)
前言 c# 托管和非托管比较重要,因为这涉及到资源的释放. 现在只要在计算机上运行的,无论玩出什么花来,整个什么概念,逃不过输入数据修改数据输出数据(计算机本质),这里面有个数据的输入,那么我们的内存 ...
- 重学c#系列——异常续[异常注意事项](七)
前言 对上节异常的补充,也可以说是异常使用的注意事项. 正文 减少try catch的使用 前面提及到,如果一个方法没有实现该方法的效果,那么就应该抛出异常. 如果有约定那么可以按照约定,如果约定有歧 ...
- 重学数据结构系列之——平衡树之SB Tree(Size Blanced Tree)
学习来源:计蒜客 平衡树 1.定义 对于每一个结点.左右两个子树的高度差的绝对值不超过1,或者叫深度差不超过1 为什么会出现这样一种树呢? 假如我们依照1-n的顺序插入到二叉排序树中,那么二叉排序树就 ...
随机推荐
- 《深入理解Elasticsearch》读书笔记 ---重点概念汇总
文章转载自: https://mp.weixin.qq.com/s?__biz=MzI2NDY1MTA3OQ==&mid=2247483918&idx=1&sn=a9f2ad3 ...
- 关于Loki中promtail组件收集日志的几点思考
promtail组件是采用docker方式运行的,配置文件也是在docker容器中,宿主机中没有挂载点,这就有问题了. 宿主机中没有挂载配置文件,也就没法修改,登录promtail的docker容器中 ...
- 【JAVA】普通IO数据拷贝次数的问题探讨
最近看到网上有些文章在讨论JAVA中普通文件IO读/写的时候经过了几次数据拷贝,如果从系统调用开始分析,以读取文件为例,数据的读取过程如下(以缓存I/O为例): 应用程序调用read函数发起系统调用, ...
- Spring让人眼前一亮的11个小技巧
前言 我们一说到spring,可能第一个想到的是 IOC(控制反转) 和 AOP(面向切面编程). 没错,它们是spring的基石,得益于它们的优秀设计,使得spring能够从众多优秀框架中脱颖而出. ...
- 为Azure-云准备一个基于Red Hat 8.x 的虚拟机镜像
由于公司最近要求部分项目上线到Azure云上,要求操作系统使用的Redhat 8.x,而且必须加固 而在Azure官网提供的镜像中,又没有Redhat,于是只有自己自定义Redhat镜像,最后加固,作 ...
- ARC148游记
A - mod M 题目链接 这道题我们可以首先对于所有的数 $%2$ ,可以证明出答案最多不超过 $2$ ,此时我们就可以把问题转化为:是否存在一个数使得序列 $a$ 中所有元素减去这个数之后的最大 ...
- 两将军问题和TCP三次握手
两将军问题,又被称为两将军悖论.两军问题, 是一个经典的计算机思想实验. 首先, 为避免混淆,我们需要认识到两将军问题虽然与拜占庭将军问题相关,但两者不是一个东西.拜占庭将军问题是一个更通用的两将军问 ...
- Hudi 数据湖的插入,更新,查询,分析操作示例
Hudi 数据湖的插入,更新,查询,分析操作示例 作者:Grey 原文地址: 博客园:Hudi 数据湖的插入,更新,查询,分析操作示例 CSDN:Hudi 数据湖的插入,更新,查询,分析操作示例 前置 ...
- 通过 Github Action 实现定时推送天气预报
偶然间,看到 GitHub Actions 教程:定时发送天气邮件 - 阮一峰的网络日志 这篇文章,没错,这个正好能打发自己的折腾之心,也能通过代码给生活引入一些变化. 还是在这里简单记录一下实现过程 ...
- `<jsp:getProperty>`动作和`<jsp:setProperty>`动作的使用在一个静态页面填写图书的基本信息,页面信息提交给其他页面,并且在其页面显示。要去将表单元素的值赋值给Java
<jsp:getProperty>动作和<jsp:setProperty>动作的使用 1.<jsp:getProperty>动作 语法格式: <jsp:get ...