当前位置: 首页 > news >正文

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())。

相关文章:

  • app逆向专题三:adb工具的使用
  • python格式化字符串漏洞
  • 想写回忆录了讲讲我的故事
  • 《汽车制造技术基础》第一次作业
  • FileOutputStream 详解与记忆方法
  • 第十六届蓝桥杯省赛JavaB组题解
  • Ansible-Playbook详解
  • 第十六届蓝桥杯大赛软件赛省赛 C/C++ 大学B组
  • 【图像处理基石】什么是抗锯齿(Anti-Aliasing)?
  • 上海AI实验室开源Intern VL3系列模型:整体文本性能优于 Qwen2.5 系列
  • maven编译jar踩坑[sqlite.db]
  • [福游宝——AI智能旅游信息查询平台]全栈AI项目-阶段一:Vite前端开荒
  • 【模块化拆解与多视角信息1】基础信息:隐藏的筛选规则——那些简历上没说出口的暗号
  • 使用 Visual Studio 2022 (VS2022) 编译 FreeCAD 1.0.0 的详细教程
  • Model Context Protocol (MCP) - 尝试创建和测试一下MCP Server
  • 探秘Transformer系列之(26)--- KV Cache优化 之 PD分离or合并
  • swift菜鸟教程29-30(泛型,访问控制)
  • 文件上传基本原理靶场实现
  • SpringBoot(一)
  • 融合动态权重与抗刷机制的网文评分系统——基于优书网、IMDB与Reddit的混合算法实践
  • 2015年做哪些网站致富/网络技术推广服务
  • 郑州网站建设公司哪家专业/网站之家
  • 合肥做网站的企业/电商网站运营
  • wordpress调用页面标题/北京网站优化专家
  • 个人域名做企业网站/本地推广平台
  • 个人网站做企业备案/郑州企业网络推广外包