C# 9 新特性之增强的foreach详解

Intro

在 C# 9 中增强了 foreach 的使用,使得一切对象都有 foreach 的可能

我们来看一段代码,这里我们试图遍历一个 int 类型的值

思考一下,我们可以怎么做使得上面的代码编译通过呢?

迭代器模式

迭代器模式,提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。

迭代器模式是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可以让外部代码透明地访问集合内部的数据。

foreach 其实是一个迭代器模式的语法糖,用来遍历一个集合中的数据,foreach 可以使用 while 来实现,比如下面这个示例:

var enumerable = Enumerable.Range(1, 10).ToArray();
foreach (var i in enumerable)
{
Console.WriteLine(i);
}

使用 while 重写之后类似下面这样的代码:

var enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}

c# 中的集合基本都实现了迭代器模式,可以直接使用 foreach 来遍历,对于自定义的类型想要支持 foreach 可以实现 IEnumerable 或 IEnumerable<T>,对于没有实现迭代器的代码,是不是可以用 foreach 呢

Enumerator

我们再来看开篇提到的问题,怎么实现支持 foreach 呢

从上面 VS 的提示我们可以看得出来,如果一个类型想要支持 foreach,有三种方式可以实现:

  • 实现 IEnumerable
  • 实现 IEnmuerable<T>
  • 添加 GetEnumerator 方法,方法返回值类型需要有 Current 属性和 MoveNext 方法,可以参考这个 IEnumerator,返回类型可以直接实现 IEnumerator 或 IEnumerator<T>

那么如果是一个别人封装的类型,能否支持 foreach 呢,从 C# 9 之后就可以了,可以添加一个 GetEnumerator 的扩展方法,类似于下面

public static class ForEachExtensions
{
public static IEnumerator<char> GetEnumerator(this int num)
{
return num.ToString().GetEnumerator();
}
}

此时如果是使用 C# 9 就可以编译通过了,如果手动设置了 LangVersion,需要修改为 9,否则会得到类似下面这样的错误

添加使用扩展方法,并启用 C# 9 语法:

More

有了这个功能之后,一切类型都是可以 foreach 的,没有实现迭代器模式的类型,只需要实现一个扩展方法就可以了

迎接 C# 9 ,万物皆可 foreach ~~

Reference

  • https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9
  • https://github.com/WeihanLi/SamplesInPractice/tree/master/CSharp9Sample
  • https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp9Sample/ForEachExtensions.cs

到此这篇关于C# 9 新特性之增强的foreach的文章就介绍到这了,更多相关C#9新特性之foreach内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C#9.0 新特性简介

    CandidateFeaturesForCSharp9 看到标题,是不是认为我把标题写错了?是的,C# 8.0还未正式发布,在官网它的最新版本还是Preview 5,通往C#9的漫长道路却已经开始.前写天收到了活跃在C#一线的BASSAM ALUGILI给我分享C# 9.0新特性,我在他文章的基础上进行翻译,希望能对大家有所帮助. 这是世界上第一篇关于C#9候选功能的文章.阅读完本文后,你将会为未来可能遇到的C# 9.0新特性做好更充分的准备. 这篇文章基于, C# 9.0候选新特性 原生大小的

  • C#9.0新特性详解——顶级程序语句(Top-Level Programs)

    1 背景与动机 通常,如果只想用C#在控制台上打印一行"Hello World!",这可不是Console.WriteLine("Hello World!");一条语句就可以搞定的,还涉及到其他必要基础代码(如定义类和入口函数Main),例如下面: using System; class Program { static void Main() { Console.WriteLine("Hello World!"); } } 就打印一句"

  • 浅谈C#9.0新特性之参数非空检查简化

    参数非空检查是缩写类库很常见的操作,在一个方法中要求参数不能为空,否则抛出相应的异常.比如: public static string HashPassword(string password) { if(password is null) { throw new ArgumentNullException(nameof(password)); } ... } 当异常发生时,调用者很容易知道是什么问题.如果不加这个检查,可能就会由系统抛出未将对象引用为实例之类的错误,这不利于调用者诊断错误. 由

  • 深入谈谈C#9新特性的实际运用

    前言 你一定会好奇:"老周,你去哪开飞机了?这么久没写博客了." 老周:"我买不起飞机,开了个铁矿,挖了一年半的石头.谁知铁矿垮了,压死了几条蜈蚣,什么也没挖着." 所以,这么丢死人的事,还是不要提了,爷爷从小教导我做人要低调-- 一转眼,.NET 5 要来了,同时也带来了 C# 9.遥想当年,老周刚接触 .NET 1.1 的时候,才刚上大学:如今已经过去13年了.岁月是把水果刀,从来不饶人啊. 老周很少去写诸如"XXX新特性"之类的文章,总觉得

  • C# 9 新特性之增强的foreach详解

    Intro 在 C# 9 中增强了 foreach 的使用,使得一切对象都有 foreach 的可能 我们来看一段代码,这里我们试图遍历一个 int 类型的值 思考一下,我们可以怎么做使得上面的代码编译通过呢? 迭代器模式 迭代器模式,提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示. 迭代器模式是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可以让外部代码透明地访问集合内部的数据. foreach 其实是一个迭代器模式的语法糖

  • webpack5新特性Asset Modules资源模块详解

    目录 正文 图片打包(asset/resource) publicPath asset/inline 模块 asset 模块 asset/source 模块 正文 webpack 可以将很多类型的文件写入最后打包的js文件,写入的方法有两种,一个是 Asset Modules 另一个是 Loaders 这一篇我们就来讨论 Asset Modules.Asset Modules(资源模块)是webpack5的新特性,它允许使用资源文件(字体,图标等)而无需配置额外 loader, webpack低

  • ES6新特性之模块Module用法详解

    本文实例讲述了ES6新特性之模块Module用法.分享给大家供大家参考,具体如下: 一.Module简介 ES6的Class只是面向对象编程的语法糖,升级了ES5的构造函数的原型链继承的写法,并没有解决模块化问题.Module功能就是为了解决这个问题而提出的. 历史上,JavaScript一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来.其他语言都有这项功能. 在ES6之前,社区制定了一些模块加载方案,最主要的有CommonJS和AMD两种.前者用

  • iOS12新特性之推送通知详解

    序言 众所周知,iOS中消息推送扮演了不可或缺的位置.不管是本地通知还是远程通知无时不刻的在影响着我们的用户体验,以致于在iOS10的时候苹果对推送大规模重构,独立了已 UserNotifications 和 UserNotificationsUI 两个单独的framework,可见重要性一斑.针对于WWDC18苹果又给我们带来了什么惊喜呢? 新特性 Grouped notifications 推送分组 Notification content extensions 推送内容扩展中的可交互和动态

  • MySQL8新特性之全局参数持久化详解

    目录 前言 全局参数持久化 写在最后 总结 参考文档: 前言 自从 2018 年发布第一版 MySQL 8.0.11 正式版至今,MySQL 版本已经更新迭代到 8.0.26,相对于稳定的 5.7 版本来说,8.0 在性能上的提升是毋庸置疑的! 随着越来越多的企业开始使用 MySQL 8.0 版本,对于 DBA 来说是一个挑战,也是一个机遇!

  • JavascriptES6新特性之map和reduce详解

    目录 说明 1.map() 代码示例: 2.reduce() 代码示例: 综合案例 总结 说明 ES6中,数组新增了map和reduce方法. 1.map() map() :接收一个函数,将原数组中的所有元素用这个函数处理后放入新数组返回. 代码示例: 有一个字符串数组,我们希望转为int数组 let arr = ['1', '20', '-5', '3']; console.log(arr) //传统写法 let newArr = arr.map(function(s) { return pa

  • Java8新特性之精简的JRE详解_动力节点Java学院整理

    Oracle公司如期发布了Java 8正式版!没有让广大javaer失望.对于一个人来说,18岁是人生的转折点,从稚嫩走向成熟,法律意味着你是完全民事行为能力人,不再收益于未成年人保护法,到今年为止,java也走过了18年,java8是一个新的里程碑,带来了前所未有的诸多特性,lambda表达式,Stream API,新的Date time api,多核并发支持,重大安全问题改进等,相信java会越来越好,丰富的类库以及庞大的开源生态环境是其他语言所不具备的,说起丰富的类库,很多同学就吐槽了,j

  • ThinkPHP3.1新特性之字段合法性检测详解

    ThinkPHP3.1版增加了表单提交的字段合法性检测,可以更好的保护数据的安全性.这一特性是3.1安全特性中的一个重要部分. 表单字段合法性检测需要使用create方法创建数据对象的时候才能生效,具体有两种方式: 一.属性定义 可以给模型配置insertFields 和 updateFields属性用于新增和编辑表单设置,使用create方法创建数据对象的时候,不在定义范围内的属性将直接丢弃,避免表单提交非法数据. insertFields 和 updateFields属性的设置采用字符串(逗

  • Redis的新特性懒惰删除Lazy Free详解

    前言 Redis4.0新增了非常实用的lazy free特性,从根本上解决Big Key(主要指定元素较多集合类型Key)删除的风险.笔者在redis运维中也遇过几次Big Key删除带来可用性和性能故障. 本文分为以下几节说明redis lazy free: lazy free的定义 我们为什么需要lazy free lazy free的使用 lazy free的监控 lazy free实现的简单分析 lazy free的定义 lazy free可译为惰性删除或延迟释放:当删除键的时候,red

  • ThinkPHP3.1新特性之内容解析输出详解

    以往版本的ThinkPHP中页面输出的过程是读取模板文件,然后进行模板解析(也支持调用第三方模板引擎解析),但是有一些情况,我们并没有定义模板文件,或者把模板文件保存在数据库里面,那么这种情况下进行页面输出的时候,我们是无法进行模板文件读取的,ThinkPHP3.1版本则针对这样的情况增加了内容解析输出的功能. 内置的模板引擎也进行了完善,如果传入的模板文件不存在的话,则会认为是传入的模板解析内容,因此,ThinkPHP3.1版的View类和Action类也做了一些相应的改进. display方

随机推荐