IEnumerator 枚举器的使用

本文详细介绍了C#中的IEnumerator枚举器概念,包括Current属性、MoveNext()、Reset()和Dispose()方法。同时,通过列举多个实战案例,如不同版本源码分析、时间操作和文件读取,深入理解枚举器的使用方法和应用场景。文章适用于熟悉C#的开发者,旨在提升对IEnumerator接口的理解和应用。

目录

一、IEnumerator 概念

二、IEnumerator 案例

1、IEnumerator C#1 最早版本源码

2、IEnumerator C#2版本源码

3、IEnumerator 时间案例 -- 实战

4、IEnumerator 文件读取案例 -- 实战


涉及知识点:  IEnumerator 、 IEnumerable

一、IEnumerator 概念

IEnumerator 枚举器: 在枚举器中实现,下标自增,数据提取
                                    属性Current        -- 当前下标位置
                                    方法:MoveNext() -- 移动到下一个
                                                Reset()         -- 复位
                                                Dispose()    -- 释放迭代

IEnumerable 枚举器接口: 只要一个类型实现了IEnumerable接口,就可以对他进行foreach
                                     方法:GetEnumerator() -- 返回循环访问集合的枚举数

二、IEnumerator 案例

1、IEnumerator C#1 最早版本源码

代码编写:

    internal class Program
    {
        static void Main(string[] args)
        {
            string[] number = { "23", "23", "245" };
            StudentIEnumerable Tom = new StudentIEnumerable(number);

            foreach (object? item in Tom)
            {
                Console.WriteLine(item);
            }
            //返回值:  23
            //        23
            //        245
            Console.WriteLine("Hello World!");
        }
    }
    //枚举接口
    public class StudentIEnumerable : IEnumerable
    {
        object[] _objValue;
        public StudentIEnumerable(object[] objValue)
        {
            this._objValue = objValue;
        }

        public IEnumerator GetEnumerator()
        {
            return new StudentIEnumerator(_objValue);
        }
    }
    //枚举器
    public class StudentIEnumerator : IEnumerator
    {
        object[] _objValue { get; }
        int _position = -1;

        public StudentIEnumerator(object[] objValue)
        {
            _objValue = objValue;
        }
        //当前值
        public object Current
        {
            get
            {
                if (_position == -1 || _position == _objValue.Length)
                {
                    return false;
                }
                return _objValue[_position];
            }
        }
        //索引向下移一个
        public bool MoveNext()
        {
            if (_position++ < _objValue.Length - 1)
            {
                return true;
            }
            return false;
        }
        //复位
        public void Reset()
        {
            _position = -1;
        }
    }

结果显示:

2、IEnumerator C#2版本源码

建议:复制,自己跑一遍

代码编写:

    class Program
    {
        static readonly string Padding = "abcd";

        static IEnumerable<int> CreateEnumerable()
        {
            Console.WriteLine("---CreateEnumerable()方法开始---");
            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine($"{i}--开始 yield ");
                Console.WriteLine($"******{Padding[i]}******");
                yield return i;
                Console.WriteLine($"{i}--结束 yield ");
            }
            yield return -1;
            Console.WriteLine("--- CreateEnumerable()方法结束---");
        }

        static void Main(string[] args)
        {
            IEnumerable<int> iterable = CreateEnumerable();
            IEnumerator<int> iterator = iterable.GetEnumerator();
            Console.WriteLine("-------------迭代开始---------");
            while (true)
            {
                Console.WriteLine("---调用MoveNext()方法");
                bool result = iterator.MoveNext();
                Console.WriteLine($"MoveNext方法返回值:{result}");
                if (!result)
                {
                    break;
                }
                Console.WriteLine($"当前指针位置:{iterator.Current}");
                Console.WriteLine();
            }
            Console.WriteLine("-------------迭代结束---------");
        }
    }

结果显示:

3、IEnumerator 时间案例 -- 实战

代码编写:

    class Program
    {
        static IEnumerable<DateTime> DataRange(DateTime dataTimeEnd)
        {
            for (DateTime i = DateTime.Now; i < dataTimeEnd; i = i.AddDays(1))
            {
                yield return i;
            }
        }

        static void Main(string[] args)
        {
            DateTime dateTimeEnd = DateTime.Now.AddDays(5);
            foreach (DateTime item in DataRange(dateTimeEnd))
            {
                Console.WriteLine(item.ToString());
            }
        }
    }

结果显示:

4、IEnumerator 文件读取案例 -- 实战

前期准备:

代码编写:

    class Program
    {
        static void Main(string[] args)
        {
            string fileName = "C:\\Users\\Rush\\Desktop\\C#\\linq查询\\123.txt";
            foreach (string line in ReadLines(fileName))
            {
                Console.WriteLine(line);
            }
        }

        static IEnumerable<string> ReadLines(string fileName)
        {
            string line;
            using (TextReader reader = File.OpenText(fileName))
            {
                while ((line = reader.ReadLine()) != null)
                {
                    yield return line;
                }
            }
        }
    }

结果显示:


如有错误,烦请批评指正

<think>首先,用户的问题是关于C#中迭代接口IEnumerable和IEnumerator使用案例。我需要基于提供的引用内容来回答这个问题。 回顾引用内容: - 引用[1]: IEnumerable接口表示可以通过IEnumerator迭代进行迭代的集合。 - 引用[2]: IEnumerable接口有一个GetEnumerator方法返回IEnumeratorIEnumerator有MoveNext、Current和Reset方法。 - 引用[3]: IEnumerable是使集合可枚举的接口,IEnumerator枚举接口。 - 引用[4]: 讨论了IEnumerable和IEnumerator的区别和作用。 - 引用[5]: 给出了手动实现IEnumerator使用迭代简化实现的例子。 用户要求提供分别使用案例,所以我需要展示IEnumerable和IEnumerator的实际应用示例。 结构化我的回答: 1. **引言**:简要解释IEnumerable和IEnumerator的作用和区别。 - IEnumerable:表示集合是可枚举的,提供GetEnumerator方法返回枚举。 - IEnumerator:实际实现迭代逻辑,有MoveNext、Current和Reset方法。 2. **使用案例**: - **IEnumerable使用案例**:自定义集合实现IEnumerable以支持foreach循环。 - **IEnumerator使用案例**:手动创建枚举来处理自定义迭代逻辑。 3. **代码示例**:提供C#代码来展示实现。 - 基于引用[5],有一个手动实现IEnumerator的例子。 - 我可以扩展或简化这些例子。 4. **生成相关问题**:回答后添加相关问题。 5. **格式要求**: - 中文回答。 - 行内数学表达式用$...$,但没有数学内容,所以可能不需要。 - 独立公式单独成段,但这里没有数学公式。 - LaTeX语法正确。 - 引用标识:在引用段落末尾添加[^数字]。 实现步骤: - 定义自定义集合类实现IEnumerable。 - 实现GetEnumerator方法返回IEnumerator。 - 手动实现IEnumerator类。 - 显示使用foreach的例子。 - 还可以展示使用yield关键字简化迭代。 从引用[5]中,提到: - MyCollection实现了IEnumerable并手动创建了MyEnumerator。 - MyCollectionWithIterator使用迭代(可能通过yield)。 所以,我可以基于此创建示例。 最终回答结构: 1. 简要介绍。 2. IEnumerable使用案例。 3. IEnumerator使用案例。 4. 相关问题。 </think>### C#中IEnumerable和IEnumerator接口的使用案例 在C#中,`IEnumerable`和`IEnumerator`接口共同支持集合的迭代功能,但它们的作用和使用场景各不相同。`IEnumerable`接口定义了一个集合为“可枚举”的类型,提供`GetEnumerator`方法返回枚举对象;而`IEnumerator`接口则负责实现实际的迭代逻辑,包括移动到下一个元素(`MoveNext`)、获取当前元素(`Current`)和重置枚举(`Reset`)。`IEnumerable`使集合能被`foreach`循环遍历,而`IEnumerator`允许开发者手动控制迭代过程。以下是分别的使用案例,我将提供代码示例来说明。 #### 1. **IEnumerable接口的使用案例** `IEnumerable`接口主要用于实现自定义集合类,使其支持标准的迭代操作(如`foreach`)。当一个类实现了`IEnumerable`,它必须提供`GetEnumerator`方法返回一个`IEnumerator`实例。这在创建自定义集合或包装现有数据时非常常见,例如实现一个简单的数字序列生成。 **代码示例**:实现自定义整数集合支持`foreach`。 ```csharp using System; using System.Collections; using System.Collections.Generic; // 自定义集合类实现IEnumerable接口 public class NumberCollection : IEnumerable<int> { private readonly int[] _numbers; public NumberCollection(int[] numbers) { _numbers = numbers; } // 实现GetEnumerator方法,返回IEnumerator实例 public IEnumerator<int> GetEnumerator() { // 使用yield关键字简化迭代实现(底层生成IEnumerator) foreach (var number in _numbers) { yield return number; // yield自动处理IEnumerator逻辑 } } // 非泛型版本(兼容旧代码) IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } class Program { static void Main() { int[] data = { 1, 2, 3, 4, 5 }; var collection = new NumberCollection(data); // 使用foreach遍历自定义集合(依赖IEnumerable) foreach (var num in collection) { Console.WriteLine(num); // 输出:1, 2, 3, 4, 5 } } } ``` **解释**:在这个案例中,`NumberCollection`类实现了`IEnumerable<int>`接口,通过`GetEnumerator`方法返回一个迭代使用`yield`关键字自动创建`IEnumerator`)。这使得`foreach`循环能遍历集合元素。这种方式简化了迭代逻辑,常用于LINQ查询或自定义数据集封装[^3]。 #### 2. **IEnumerator接口的使用案例** `IEnumerator`接口用于手动控制迭代过程,适用于需要精细管理迭代状态的自定义场景,例如实现分步迭代、暂停/恢复迭代或自定义过滤规则。直接实现`IEnumerator`允许开发者覆盖`MoveNext`、`Current`和`Reset`方法,提供更灵活的迭代控制,比如在数据流处理中。 **代码示例**:手动实现IEnumerator创建一个跳过偶数的迭代。 ```csharp using System; using System.Collections; using System.Collections.Generic; // 自定义迭代类实现IEnumerator接口 public class OddNumberEnumerator : IEnumerator<int> { private int[] _numbers; private int _currentIndex = -1; // 初始位置在第一个元素之前 public OddNumberEnumerator(int[] numbers) { _numbers = numbers; } // MoveNext移动到下一个元素,跳过偶数 public bool MoveNext() { _currentIndex++; while (_currentIndex < _numbers.Length) { if (_numbers[_currentIndex] % 2 != 0) // 只处理奇数 return true; _currentIndex++; } return false; // 无更多元素 } // Current属性获取当前元素 public int Current { get { if (_currentIndex < 0 || _currentIndex >= _numbers.Length) throw new InvalidOperationException("迭代未初始化或已结束"); return _numbers[_currentIndex]; } } // 显式实现非泛型版本 object IEnumerator.Current => Current; // Reset方法(一般不建议使用,但需实现) public void Reset() { _currentIndex = -1; // 重置位置 } // 清理资源 public void Dispose() { } } // 集合类使用自定义IEnumerator public class SkipEvenCollection : IEnumerable<int> { private readonly int[] _numbers; public SkipEvenCollection(int[] numbers) { _numbers = numbers; } public IEnumerator<int> GetEnumerator() { return new OddNumberEnumerator(_numbers); // 返回手动实现的IEnumerator } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } class Program { static void Main() { int[] data = { 1, 2, 3, 4, 5 }; var collection = new SkipEvenCollection(data); // 手动控制迭代(使用IEnumerator接口) var enumerator = collection.GetEnumerator(); while (enumerator.MoveNext()) // 手动调用MoveNext { Console.WriteLine(enumerator.Current); // 输出:1, 3, 5 (跳过偶数) } } } ``` **解释**:这里,`OddNumberEnumerator`类手动实现了`IEnumerator<int>`接口,定义了`MoveNext`方法来跳过偶数元素。`SkipEvenCollection`类(实现了`IEnumerable`)返回这个自定义枚举。这适合需要复杂迭代逻辑的场景,如数据过滤或分页查询[^2][^5]。 #### 总结 - **IEnumerable案例**:主要用于集合封装,支持`foreach`遍历,代码简洁(如使用`yield`)。 - **IEnumerator案例**:用于低级迭代控制,如自定义迭代规则或状态管理。 两者通常结合使用:`IEnumerable`提供迭代入口,`IEnumerator`执行具体迭代。实际开发中,推荐优先使用`yield`(自动生成`IEnumerator`),除非需要精细控制迭代过程[^4][^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值