C# --- IEnumerable 和 IEnumerator

C# --- IEnumerable 和 IEnumerator

  • IEnumerable
  • IEnumerator
  • IEnumerable 和 IEnumerator 的作用
  • 手动实现 IEnumerable
  • IEnumerable vs. IQueryable
  • 为什么有了ienumerator还需要ienumerable

IEnumerable

  • 在C#中,IEnumerable 是一个核心接口,用于表示一个可迭代的集合。它是实现迭代模式的基础,允许你通过 foreach 循环遍历集合中的元素
  • IEnumerable 是一个接口,属于 System.Collections 命名空间。它的泛型版本 IEnumerable 位于 System.Collections.Generic 中。
  • 作用:标记一个对象可以被迭代(即支持 foreach 循环)。
  • 核心方法:GetEnumerator(),返回一个 IEnumerator 对象,用于逐个访问集合中的元素。
public interface IEnumerable
{IEnumerator GetEnumerator();
}// 泛型版本(更常用):
public interface IEnumerable<out T> : IEnumerable
{IEnumerator<T> GetEnumerator();
}

IEnumerator

  • IEnumerator 是实际执行迭代的接口,相当于Java里的iterator, 他定义了三个关键方法:
  • MoveNext():移动到集合的下一个元素,返回 bool 表示是否成功。
  • Current:获取当前元素的值。
  • Reset():重置迭代器到初始位置(通常不常用)
public interface IEnumerator
{bool MoveNext();object Current { get; }void Reset();
}// 泛型版本:
public interface IEnumerator<out T> : IEnumerator, IDisposable
{T Current { get; }
}

IEnumerable 和 IEnumerator 的作用

  • 统一迭代方式:任何实现 IEnumerable 的类型都可以用 foreach 遍历。
  • 支持 LINQ:LINQ 的查询操作(如 Where、Select)基于 IEnumerable,实现延迟执行。
  • 抽象集合类型:允许代码操作抽象的集合(IEnumerable<T>),而非具体类型(如 List),提高灵活性。

手动实现 IEnumerable

using System;
using System.Collections;public class MyCollection : IEnumerable
{private int[] _data = { 1, 2, 3 };public IEnumerator GetEnumerator(){return new MyEnumerator(_data);}
}public class MyEnumerator : IEnumerator
{private int[] _data;private int _index = -1;public MyEnumerator(int[] data){_data = data;}public object Current => _data[_index];public bool MoveNext(){_index++;return _index < _data.Length;}public void Reset(){_index = -1;}
}// 使用:
var collection = new MyCollection();
foreach (var num in collection)
{Console.WriteLine(num); // 输出 1, 2, 3
}

IEnumerable vs. IQueryable

  • IEnumerable:
    用于内存中集合(如 List、数组)。
    LINQ 操作由 C# 编译器处理(如 Where 转换为委托)。
  • IQueryable:
    用于外部数据源(如数据库)。
    LINQ 操作转换为表达式树(如 SQL 查询),由提供程序解析

为什么有了ienumerator还需要ienumerable

IEnumerable:

  • 角色:表示一个集合是“可迭代的”。
    核心功能:通过 GetEnumerator() 方法返回一个迭代器(IEnumerator 对象)。
  • 意义:提供统一的接口,让所有集合类型(如数组、List、自定义集合)都能被 foreach 遍历。

IEnumerator:

  • 角色:实际控制迭代过程(移动指针、获取当前元素)。
  • 核心功能:通过 MoveNext() 和 Current 实现逐个元素的遍历。
  • 意义:封装迭代状态(如当前索引),确保多次遍历互不干扰

场景假设

  • 假设一个集合类直接实现 IEnumerator, 如果两个 foreach 同时遍历同一个 BadList 实例,它们的 _index 会互相干扰:无法支持并发迭代:同一实例的迭代状态会被覆盖
public class BadList : IEnumerator<int>
{private int[] _data = { 1, 2, 3 };private int _index = -1;public int Current => _data[_index];object IEnumerator.Current => Current;public bool MoveNext(){_index++;return _index < _data.Length;}public void Reset() => _index = -1;public void Dispose() { }
}
var badList = new BadList();
foreach (var num in badList) { /* 第一次遍历 */ } // 输出 1,2,3
foreach (var num in badList) { /* 第二次遍历 */ } // 无输出(索引已到末尾)

正确做法:IEnumerable + IEnumerator

public class GoodList : IEnumerable<int>
{private int[] _data = { 1, 2, 3 };public IEnumerator<int> GetEnumerator(){// 每次调用返回一个新的迭代器return new GoodListEnumerator(_data);}// 显式实现非泛型接口IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}public class GoodListEnumerator : IEnumerator<int>
{private int[] _data;private int _index = -1;public GoodListEnumerator(int[] data) => _data = data;public int Current => _data[_index];object IEnumerator.Current => Current;public bool MoveNext(){_index++;return _index < _data.Length;}public void Reset() => _index = -1;public void Dispose() { }
}
  • 状态隔离:每次 foreach 会调用 GetEnumerator() 生成新的 IEnumerator 实例,确保每次遍历独立。
  • 并发安全:多个遍历操作互不影响。
  • 简化代码:foreach 自动管理迭代器生命周期(调用 Dispose())。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/76025.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

镜舟科技助力某大型电网企业破解数据架构升级难题,打造国产化湖仓标杆

在 “十四五” 规划全面推进国产化替代的背景下&#xff0c;某大型电网企业联合镜舟科技与腾讯云&#xff0c;基于全球领先的开源分析型数据库 StarRocks 及腾讯 TBDS 大数据平台&#xff0c;构建电力行业国产化湖仓一体架构。该项目实现 PB 级电力数据的统一管理&#xff0c;为…

Spark-SQL核心编程3

数据加载与保存 通用方式&#xff1a; SparkSQL 提供了通用的保存数据和数据加载的方式。这里的通用指的是使用相同的API&#xff0c;根据不同的参数读取和保存不同格式的数据&#xff0c;SparkSQL 默认读取和保存的文件格式为parquet 数据加载方法&#xff1a; spark.read.lo…

使用HTML + CSS + JS,编写一个台球追分计分器

目录 一.代码 二.效果展示 三.该计分器的优点 一.代码 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><…

LLM小白自学笔记:1.两种指令微调

一、LoRA 简单来说&#xff0c;LoRA不直接调整个大模型的全部参数&#xff08;那样太费资源&#xff09;&#xff0c;而是在模型的某些层&#xff08;通常是注意力层&#xff09;加个“旁路”——两个小的矩阵&#xff08;低秩矩阵&#xff09;。训练时只更新这俩小矩阵&#x…

2026《数据结构》考研复习笔记一(C++基础知识)

C基础知识复习 一、数据类型二、修饰符和运算符三、Lambda函数和表达式四、数学函数五、字符串六、结构体 一、数据类型 1.1基本类型 基本类型 描述 字节&#xff08;位数&#xff09; 范围 char 字符类型&#xff0c;存储ASCLL字符 1&#xff08;8位&#xff09; -128…

基于骨骼识别的危险动作报警分析系统

基于骨骼识别的危险动作报警分析系统 【包含内容】 【一】项目提供完整源代码及详细注释 【二】系统设计思路与实现说明 【三】基于骨骼识别算法的实时危险行为预警方案 【技术栈】 ①&#xff1a;系统环境&#xff1a;Windows 10/11、macOS Ventura、Ubuntu 20.04 ②&#x…

【双指针】四数之和(medium)

四数之和&#xff08;medium&#xff09; 题⽬描述&#xff1a;解法&#xff08;排序 双指针&#xff09;算法思路&#xff1a; C 算法代码&#xff1a;Java 算法代码&#xff1a; 题⽬链接&#xff1a;18. 四数之和 题⽬描述&#xff1a; 给你⼀个由 n 个整数组成的数组 num…

Flask+Influxdb+grafna构建电脑性能实时监控系统

Influx下载地址&#xff0c;这里下载了以下版本influxdb-1.8.5_windows_amd64.zip 运行前需要先启动Influx数据库&#xff1a; 管理员方式运行cmd->F:->cd F:\influxdb\influxdb-1.8.5-1->influxd -config influxdb.conf&#xff0c;以influxdb.conf配置文件启动数…

如何在Keil中配置国民技术N32G系列MCU开发环境

如何在Keil及Jlink中搭建国民技术N32G系列MCU开发环境 根据自己的MCU型号&#xff08;我这里的型号是N32G452REL7&#xff09;访问国民技术官网&#xff0c;依次从N32G通用MCU-技术资源-固件和软件-软件开发套件&#xff0c;获取对应MCU型号的SDK&#xff0c;也可点击这里从网盘…

微软承认Win11出现极端错误,只能强制关机或重装系统

最近&#xff0c;不少使用 Windows 11 的用户反映&#xff0c;在系统更新后&#xff0c;“Windows Hello”突然失效&#xff0c;原本便捷的人脸识别和PIN登录功能统统无法使用。更糟的是&#xff0c;有人在重置系统后直接被挡在系统门外&#xff0c;这让人不禁发问&#xff1a;…

【android bluetooth 协议分析 02】【bluetooth hal 层详解 1】【uart 介绍】

一、什么是 UART&#xff1f; UART&#xff08;Universal Asynchronous Receiver/Transmitter&#xff09; 是一种 串行通信协议&#xff0c;它的特点是通信时不需要专门的时钟信号&#xff08;叫做“异步”通信&#xff09;&#xff0c;常用于两个设备之间的简单数据通信&…

天元证券|奶粉行业结构性回暖 乳企竞速全龄化、国际化

在过去几年中&#xff0c;中国婴配粉市场经历了量价齐增&#xff0c;量减价增&#xff0c;量减价减的三个周期。历经多年行业深度洗牌与竞争格局重塑&#xff0c;2024年中国婴配粉市场回暖态势愈发清晰可辨。 日前&#xff0c;包括中国飞鹤、澳优、健合集团在内的多家奶粉股披露…

第3.1节 调用链路分析简介

调用链路&#xff08;Call Chain / Call Path&#xff09; 是程序在执行过程中&#xff0c;按照调用顺序形成的函数、模块或组件之间的依赖关系链条&#xff0c;完整记录了从程序入口到当前执行点的动态调用路径。它反映了代码执行的逻辑流程&#xff0c;是分析程序行为、调试问…

System.Security.Cryptography.CryptographicException“填充无效,无法被移除。”

这个异常通常发生在以下几种情况&#xff1a; 1.密文损坏&#xff1a;密文在传输或存储过程中被篡改或损坏。 2.密钥不匹配&#xff1a;用于解密的密钥与加密时使用的密钥不同。 3.填充模式不匹配&#xff1a;加密时使用的填充模式与解密时指定的填充模式不一致。 4.使用了不正…

【网络入侵检测】Suricata之数据包内容匹配

【作者主页】只道当时是寻常 【专栏介绍】入侵检测。专注网络、主机安全&#xff0c;欢迎关注与评论。 1. 概要 本文详细介绍了网络入侵检测系统&#xff08;如 Suricata&#xff09;中用于检查数据包或流有效载荷的 Payload 关键字。content 用于匹配数据包内容&#xff0c;默…

Spring Boot 整合 Redis 实现点赞功能:从基础到实践

在当今互联网应用开发中&#xff0c;点赞功能几乎成为了各类内容平台的标配。它不仅能增加用户与内容之间的互动&#xff0c;还能直观地反映内容的受欢迎程度。本文将详细介绍如何使用 Spring Boot 整合 Redis 来实现一个简单的文章点赞功能&#xff0c;让你轻松掌握这一实用技…

openGauss DataVec + Dify,快速搭建你的智能助手平台

在当今数字化和智能化的时代&#xff0c;大语言模型&#xff08;LLM&#xff09;的应用正以前所未有的速度改变着各个领域的工作方式和用户体验。Dify 作为一个开源的大语言模型应用开发平台&#xff0c;为开发者们提供了便捷且强大的工具&#xff0c;助力构建从基础智能体到复…

OpenLayers:extent与view extent 介绍

一、范围的概念 1.什么是范围&#xff1f; 在Openlayers中范围&#xff08;Extent&#xff09;是用于表示地理空间区域的一种概念。它通常由一个数字数组构成&#xff0c;数组中的内容为&#xff1a;[最小x坐标&#xff0c;最小y坐标&#xff0c;最大x坐标&#xff0c;最大y坐…

can‘t set boot order in virtualbox

Boot order setting is ignored if UEFI is enabled https://forums.virtualbox.org/viewtopic.php?t99121 如果勾选EFI boot order就是灰色的 传统BIOS就是可选的 然后选中任意介质&#xff0c;通过右边的上下箭头调节顺序&#xff0c;最上面的应该是优先级最高的 然后就…

如何在 Kali 上解决使用 evil-winrm 时 Ruby Reline 的 quoting_detection_proc 警告

在使用 Kali Linux 运行 Ruby 工具&#xff08;例如 evil-winrm&#xff09;时&#xff0c;你可能会遇到以下警告&#xff1a; Warning: Remote path completions is disabled due to ruby limitation: undefined method quoting_detection_proc for module Reline这个警告会导…