首先我们去core的源码中去找IEnumerable发现并没有,如下

Core中应该是直接使用.net中对IEnumerable的定义

自己实现迭代器

  迭代器是通过IEnumerable和IEnumerator接口来实现的,今天我们也来尝试实现自己的迭代器。

  首先来看看这两个接口:

internal interface IEnumerable
{
[DispId(-)]
System.Collections.IEnumerator GetEnumerator();
}
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}

  并没有想象的那么复杂。其中IEnumerable只有一个返回IEnumerator的GetEnumerator方法。而IEnumerator中有两个方法加一个属性。

  接下来,我们继承IEnumerable接口并实现:

public class MyIEnumerable : IEnumerable
{
private string[] strList;
public MyIEnumerable(string[] strList)
{
this.strList=strList;
}
public IEnumerator GetEnumerator()
{
return new MyIEnumerator(strList);
}
}
public class MyIEnumerator:IEnumerator
{
private string[] strList;
private int position;
public MyIEnumerator(string[] strList)
{
this.strList=strList;
position=-;
}
public object Current
{
get{ return strList[position];}
}
public bool MoveNext()
{
position++;
if (position<strList.Length)
{
return true;
}
return false;
}
public void Reset()
{
position=-;
}
}

下面使用原始的方式调用:

static void Main(string[] args)
{
string[] strList=new string[]{"",""};
MyIEnumerable my =new MyIEnumerable(strList);
var enumerator=my.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
//enumerator.Current=""; 这会报错
}
Console.WriteLine("-------------------------------");
foreach (var item in my)
{
Console.WriteLine(item);
}
}

这两种取值方式基本等效,因为实际clr编译后生成的代码是相同的。

由此可见,两者有这么个关系:

我们可以回答一个问题了“为什么在foreach中不能修改item的值?”:

我们还记得IEnumerator的定义吗,接口的定义就只有get没有set。所以我们在foreach中不能修改item的值。

yield的使用

  你肯定发现了我们自己去实现IEnumerator接口还是有些许麻烦,并且上面的代码肯定是不够健壮。对的,.net给我们提供了更好的方式。

public IEnumerator GetEnumerator()
{
//return new MyIEnumerator(strList);
for (int i = ; i < strList.Length; i++)
{
yield return strList[i];
}
}

你会发现我们连MyIEnumerator都没要了,也可以正常运行。太神奇了。yield到底为我们做了什么呢?

好家伙,我们之前写的那一大坨。你一个yield关键字就搞定了。最妙的是这块代码:

这就是所谓的状态机吧!

  我们调用GetEnumerator的时候,看似里面for循环了一次,其实这个时候没有做任何操作。只有调用MoveNext的时候才会对应调用for循环。

为什么Linq to Object中要返回IEnumerable?

因为IEnumerable是延迟加载的每次访问的时候才取值。也就是我们在Lambda里面写的where、select并没有循环遍历(只是在组装条件)只有在ToList或foreache的时候才真正去集合取值了。这样大大提高了性能。

自己实现MyWhere:

public class MyIEnumerable : IEnumerable
{
private string[] strList;
public MyIEnumerable(string[] strList)
{
this.strList=strList;
}
public IEnumerator GetEnumerator()
{
//return new MyIEnumerator(strList);
for (int i = ; i < strList.Length; i++)
{
yield return strList[i];
}
}
public IEnumerable<string> MyWhere(Func<string,bool> func)
{
foreach (string item in this)
{
if (func(item))
{
yield return item;
}
}
}
}

FirstOrDefault的实现

内部调用了TryGetFirst。

private static TSource TryGetFirst<TSource>(this IEnumerable<TSource> source, out bool found)
{
if (source == null)
{
throw Error.ArgumentNull(nameof(source));
} if (source is IPartition<TSource> partition)
{
return partition.TryGetFirst(out found);
} if (source is IList<TSource> list)
{
if (list.Count > )
{
found = true;
return list[];
}
}
else
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
//同样调用了MoveNext方法
if (e.MoveNext())
{
found = true;
//Current属性在我们的自定义实现里面也有出现
return e.Current;
}
}
} found = false;
return default(TSource);
}

不传入筛选的实现

private static TSource TryGetFirst<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, out bool found)
{
if (source == null)
{
throw Error.ArgumentNull(nameof(source));
} if (predicate == null)
{
throw Error.ArgumentNull(nameof(predicate));
} if (source is OrderedEnumerable<TSource> ordered)
{
return ordered.TryGetFirst(predicate, out found);
} foreach (TSource element in source)
{
//循环,直接返回第一个符合条件的对象
if (predicate(element))
{
found = true;
return element;
}
} found = false;
return default(TSource);
}

传入筛选的实现

源码地址

https://gitee.com/qixinbo/MyKestrelServer/tree/master/DataStruct/EnumerableStudy

本文参考《农码一生》

https://www.cnblogs.com/zhaopei/p/5769782.html

Core源码(四)IEnumerable的更多相关文章

  1. 一个由正则表达式引发的血案 vs2017使用rdlc实现批量打印 vs2017使用rdlc [asp.net core 源码分析] 01 - Session SignalR sql for xml path用法 MemCahe C# 操作Excel图形——绘制、读取、隐藏、删除图形 IOC,DIP,DI,IoC容器

    1. 血案由来 近期我在为Lazada卖家中心做一个自助注册的项目,其中的shop name校验规则较为复杂,要求:1. 英文字母大小写2. 数字3. 越南文4. 一些特殊字符,如“&”,“- ...

  2. 一起来看CORE源码(一) ConcurrentDictionary

    先贴源码地址 https://github.com/dotnet/corefx/blob/master/src/System.Collections.Concurrent/src/System/Col ...

  3. ASP.NET Core[源码分析篇] - WebHost

    _configureServicesDelegates的承接 在[ASP.NET Core[源码分析篇] - Startup]这篇文章中,我们得知了目前为止(UseStartup),所有的动作都是在_ ...

  4. ASP.NET Core[源码分析篇] - Authentication认证

    原文:ASP.NET Core[源码分析篇] - Authentication认证 追本溯源,从使用开始 首先看一下我们通常是如何使用微软自带的认证,一般在Startup里面配置我们所需的依赖认证服务 ...

  5. DOTNET CORE源码分析之IOC容器结果获取内容补充

    补充一下ServiceProvider的内容 可能上一篇文章DOTNET CORE源码分析之IServiceProvider.ServiceProvider.IServiceProviderEngin ...

  6. ASP.NET Core源码学习(一)Hosting

    ASP.NET Core源码的学习,我们从Hosting开始, Hosting的GitHub地址为:https://github.com/aspnet/Hosting.git 朋友们可以从以上链接克隆 ...

  7. asp.net core源码地址

    https://github.com/dotnet/corefx 这个是.net core的 开源项目地址 https://github.com/aspnet 这个下面是asp.net core 框架 ...

  8. ASP .NET CORE 源码地址

    ASP .NET CORE 源码地址:https://github.com/dotnet/ 下拉可以查找相应的源码信息, 例如:查找 ASP .NET CORE Microsoft.Extension ...

  9. .net core 源码解析-web app是如何启动并接收处理请求

    最近.net core 1.1也发布了,蹒跚学步的小孩又长高了一些,园子里大家也都非常积极的在学习,闲来无事,扒拔源码,涨涨见识. 先来见识一下web站点是如何启动的,如何接受请求,.net core ...

随机推荐

  1. IPv6升级测试指南(Android/iOS/Mac)

    目录 我们升级到IPv6的原因 测试的时候的注意要点 Android/IOS/MAC测试总结 Android测试IPv6的方法 IOS端测试IPv6的方法 MAC浏览器端测试IPv6的方法 升级IPV ...

  2. MySql索引背后的数据结构及算法

    本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree ...

  3. 第一个月.day1

    1. 编辑器下载 推荐的是hbulider     开发环境 2. 浏览器 推荐chrome 谷歌浏览器学习 3. 建立技术笔记 推荐博客园 Web 本月任务 搭建静态网页. 静态页面:不需要网络请求 ...

  4. ROS基础-基本概念和简单工具(1)

    1.什么是ROS? Robot operating System ,简单说机器人操作系统,弱耦合的分布式进程框架,通过进程间的消息传递和管理.实现硬件抽象和设备控制. 2.节点(node) node ...

  5. 什么是面向对象编程(OOP)?

    Java 程序员第一个要了解的基础概念就是:什么是面向对象编程(OOP)? 玩过 DOTA2 (一款推塔杀人的游戏)吗?里面有个齐天大圣的角色,欧洲战队玩的很溜,国内战队却不怎么会玩,自家人不会玩自家 ...

  6. 为什么老外不愿意用MyBatis?

    作者:陈龙 www.zhihu.com/question/309662829 Spring 团队的Josh Long自己在Twitter上做了一个调查.1625次投票,样本量不算大,但也能说明问题.和 ...

  7. 常用类-ExcelHelper

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...

  8. CAD转PDF的软件哪个比较好用?用这两个很方便

    大家都知道编辑CAD图纸是需要借助CAD制图软件来进行绘制的,而且CAD制图软件很多的设计师们都在使用.但是CAD中的图纸格式为dwg格式的,不想要使用CAD软件来查看图纸的话,就需要将CAD转换成P ...

  9. 微信小程序支付功能 C# .NET开发

    微信小程序支付功能的开发的时候坑比较多,不过对于钱的事谨慎也是好事.网上关于小程序支付的实例很多,但是大多多少有些问题,C#开发的更少.此篇文档的目的是讲开发过程中遇到的问题做一个备注,也方便其他开发 ...

  10. (day57)九、多对多创建的三种方式、Forms组件

    目录 一.多对多三种创建方式 (一)全自动 (二)纯手撸(基本不用) (三)半自动(推荐使用) 二.forms组件 (一)校验数据 (1)常用内置字段及参数 (2)内置的校验器 (3)HOOK方法 ( ...