先说IEnumerable,我们每天用的foreach你真的懂它吗?

转之:http://www.cnblogs.com/zhaopei/p/5769782.html

我们先思考几个问题:

  1. 为什么在foreach中不能修改item的值?
  2. 要实现foreach需要满足什么条件?

接下来,先开始我们的正文。

自己实现迭代器

.net中迭代器是通过IEnumerable和IEnumerator接口来实现的,今天我们也来依葫芦画瓢。

首先来看看这两个接口的定义:



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

接下来开发画瓢,我们继承IEnumerable接口并实现:



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


有朋友开始说了,我们平时都是通过foreache来取值的,没有这样使用过啊。好吧,我们来使用foreach循环:


为什么说基本上是等效的呢?我们先看打印结果,在看反编译代码。


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


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

我们还记得IEnumerator的定义吗


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

我们再来回答第二个问题:“要实现foreach需要满足什么条件?”:

必须实现IEnumerable接口?NO


我们自己写的MyIEnumerable删掉后面的IEnumerable接口一样可以foreach(不信?自己去测试)。

所以要可以foreach只需要对象定义了GetEnumerator无参方法,并且返回值是IEnumerator或其对应的泛型。细看下图:


也就是说,只要可以满足这三步调用即可。不一定要继承于IEnumerable。有意思吧!下次面试官问你的时候一定要争个死去活来啊,哈哈!




<think>好的,我现在需要帮助用户理解C#中的IEnumerable接口。首,我得回顾一下IEnumerable的基本定义和用途。根据用户提供的引用[1],IEnumerable接口定义了一个GetEnumerator方法,返回IEnumerator对象。这明它的主要作用是用来支持集合的迭代。 接下来,用户可能想知道为什么需要这个接口。我记得在引用[3]中提到,IEnumerable和IEnumerator一起实现迭代器模式,允许使用foreach遍历集合。比如字符串可以遍历,就是因为实现了IEnumerable。这里可能需要举例子明,比如字符串的foreach用法。 然后,用户可能对IEnumerable的用途和应用场景感兴趣。我需要分点列出,比如支持foreach遍历、延迟执行(LINQ查询)、兼容性等。引用[2]提到IEnumerable和IQueryable的区别,这里可以提到IEnumerable适用于内存集合,而IQueryable用于数据库查询,但用户的问题主要围绕IEnumerable,所以可能不需要深入比较,但可以作为扩展点。 用户还可能关心如何实现自己的IEnumerable。根据引用[3]中的例子,可以使用yield return简化实现。这里需要展示一个自定义集合的代码示例,比如实现一个简单的集合类,并演示如何用foreach遍历。 另外,用户可能遇到初始化集合的问题,引用[4]指出集合初始化必须使用new,不能省略。这可能和IEnumerable使用场景相关,但用户的问题可能更关注接口本身,所以这部分可以作为补充,或者在相关问题中提到。 最后,需要生成相关问题,帮助用户进一步学习。比如与IEnumerator的关系、延迟执行特性、性能优化等。这些应该基于引用的内容,比如引用[5]提到的using语句和资源管理,但可能和IEnumerable关系不大,所以可能不涉及。 总结回答结构:定义IEnumerable,再讲用途,然后代码示例,最后相关问题。确保所有数学公式用$...$,独立公式用$$...$$,但这里可能涉及较少数学内容。检查LaTeX语法正确,使用中文,引用正确标注。</think>### IEnumerable 接口的定义与用途(C#/.NET) #### 1. **IEnumerable 的定义** `IEnumerable` 是 C#/.NET 中用于支持集合迭代的核心接口,其定义如下: ```csharp public interface IEnumerable { IEnumerator GetEnumerator(); } ``` 它仅包含一个方法 `GetEnumerator()`,返回一个 `IEnumerator` 对象,用于遍历集合中的元素[^1]。 #### 2. **核心用途** `IEnumerable` 的主要作用包括: - **支持 `foreach` 遍历** 任何实现 `IEnumerable` 的集合(如数组、`List<T>`、`Dictionary<TKey, TValue>`)均可通过 `foreach` 循环遍历。例如: ```csharp string str = "hello"; foreach (char c in str) { Console.WriteLine(c); // 输出每个字符 } ``` 字符串可遍历正是因为其实现了 `IEnumerable`[^3]。 - **实现延迟执行** 在 LINQ 查询中,`IEnumerable` 支持延迟加载,即查询不会立即执行,而是在实际迭代时触发。例如: ```csharp IEnumerable<int> numbers = Enumerable.Range(1, 10).Where(x => x % 2 == 0); // 此处未真正执行查询,直到调用 foreach 或 ToList() ``` - **兼容性** 作为最基础的集合接口,`IEnumerable` 可与其他集合类型(如 `List<T>`、数组)无缝交互。 #### 3. **实现自定义集合** 若需自定义集合类型,可通过实现 `IEnumerable` 接口支持迭代。例如,使用 `yield return` 简化实现: ```csharp public class SimpleCollection : IEnumerable { private int[] _data = { 1, 2, 3 }; public IEnumerator GetEnumerator() { foreach (int item in _data) { yield return item; // 生成迭代器 } } } // 使用示例 foreach (int num in new SimpleCollection()) { Console.WriteLine(num); // 输出 1, 2, 3 } ``` `yield return` 会自动生成状态机管理迭代过程[^3]。 #### 4. **与其他接口的关系** - **`IEnumerator`** `IEnumerable` 的 `GetEnumerator()` 返回 `IEnumerator`,后者提供 `MoveNext()` 和 `Current` 方法控制迭代逻辑。 - **泛型版本 `IEnumerable<T>`** 泛型版本提供类型安全,避免装箱拆箱开销,例如 `List<int>` 实现了 `IEnumerable<int>`。 #### 5. **初始化与使用注意事项** - 集合初始化必须显式使用 `new` 创建实例(如 `IList<string> list = new List<string> { "a", "b" };`)[^4]。 - 资源管理:若迭代器涉及非托管资源(如文件句柄),需结合 `IDisposable` 和 `using` 语句确保释放[^5]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值