有关IEnumerable和IEnumerator的问题

我使用以下代码使myClass使用foreach。 但我对编程很新,并且在理解下面的代码时遇到一些困难。 我在评论中描述了我的问题。 我很感激提供一些信息。

public class MyClass : IEnumerable { //1) What is IEnumerator for? // Whats the difference between IEnumerator and IEnumerable public IEnumerator GetEnumerator() { yield return "first"; yield return "second"; } //2) What is it for? It just calls above method IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } //3) Lastly what benefits I have from implementing genetic interface //IEnumerable instead of just IEnumerable 

IEnumerator和IEnumerable有什么区别?

杰森的回答很好,但我想我只想补充一下我对此的看法。 想象一下你有一个序列:

 1, 1, 2, 3, 5, 8, 13, ... 

现在假设你有一个箭头指向该序列的某个位置:

 1, 1, 2, 3, 5, 8, 13, ... ^ 

“箭头”是可以做两件事的对象。 首先,它可以为您提供它所指向的东西。 其次,它可以使自己指向下一件事。

IEnumerator是一个箭头。 它有一个属性Current,它为您提供它所指向的东西。 它有一个方法,MoveNext()使自己指向下一件事。

你怎么在第一时间得到一个箭头? 你需要一个箭头工厂。 你向工厂询问一个箭头,它会给你一个指向序列中第一个元素的箭头。

IEnumerable是一个箭头工厂。 它有一个方法GetEnumerator,它为您提供了序列的第一个元素的箭头。

这个方案的一个很好的特性是你可以有多个箭头指向同一序列中的不同位置。

实现通用接口IEnumerable而不仅仅是IEnumerable有什么好处?

假设序列是整数。 如果你实现IEnumerable那么当你说

 foreach(int x in mysequence) 

实际上会做的是将序列中的int转换为object,装箱整数,然后立即将对象取消装回整数,为每个操作添加一个完全不必要的内存分配。 如果编译器知道序列是整数,那么它可以跳过不必要的装箱操作。

假设序列是字符串。 如果您实现IEnumerable那么您可以说:

 string first = mysequence.First(); 

如果你不这样做,那么你必须说

 string first = (string)mysequence.First(); 

这是不必要的,容易出错。 而不是通过类型为字符串的强制转换来指示编译器,您可以通过使用类型系统简单地保证类型是字符串。

1)什么是IEnumerator ? 什么是IEnumeratorIEnumerable之间的区别?

IEnumerator是一个接口,它表示允许枚举序列的方法。 IEnumeratorIEnumerable之间的区别在于前者表示允许枚举序列的对象的契约,后者表示可以枚举的序列的对象的契约。

 public IEnumerator GetEnumerator() { yield return "first"; yield return "second"; } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } 

2)它的用途是什么? 它只是调用上面的方法。

前者表示合同IEnumerable上方法GetEnumerator的实现。 后者表示合同IEnumerable上方法GetEnumerator的显式实现。 问题是两个契约都有一个名为GetEnumerator但具有不同返回类型的方法,因此方法不能同时满足这两个契约(任何实现IEnumerable类也必须实现IEnumerableIEnumerable : IEnumerable )。 后者调用IEnumerable.GetEnumerator的实现,因为这是一个合理的实现,它将IEnumerator作为IEnumerator : IEnumerator

3)最后我实现通用接口IEnumerable而不仅仅是IEnumerable有什么好处?

打字很强。 您知道序列IEnumerable中的元素都是String实例,而您不知道IEnumerable实例,并且可能最终尝试将后者的元素强制转换为String的实例。

这是IEnumerable的声明:

 public interface IEnumerable : IEnumerable { IEnumerator GetEnumerator(); } 

你别无选择,你必须实现非通用的IEnumerable接口。 如果省略IEnumerable.GetEnumerator()实现,则会出现编译错误。 这是.NET 1.x天遗留下来的行李,其中尚未提供generics,以及.NET 2.0需要支持与.NET 1.x程序集互操作的过渡期。 我们坚持不懈。

1)什么是IEnumerator?

IEnumerator是MoveNext()和Current成员的真正工作部分。

什么是IEnumerator和IEnumerable之间的区别

IEnumerable是集合的接口,表示它具有GetEnumerator()。

2)[非genericsGetEnumerator]它的用途是什么? 它只是调用上面的方法

非generics方法只是为了向后兼容。 请注意,通过使用显式实现,它尽可能地“移出视线”。 实施它是因为你必须忘记它。

3)最后我实现遗传接口IEnumerable而不仅仅是IEnumerable有什么好处

当与foreach使用时,adavantage很小,因为foreach将输入循环变量。 它会让你在foreach中使用var

 foreach (var s in myClassInstance) // needs `IEnumerable` foreach (string s in myClassInstance) // works with `IEnumerable` as well 

但是对于IEnumerable你还有一个到其他区域的类型安全接口,最值得注意的是LINQ:

 MyClass mc = new MyClass (); string s = mc.FirstOrDefault(); 

GetEnumerator自从将generics引入该语言之前就已存在,为了不破坏预先存在的代码,默认方法调用通用实现。

使用generics枚举,类的使用者不需要在迭代时将每个项目转换为字符串。

关于第3个问题(为什么要使用generics?),这里有一些答案:

我们应该使用Generic Collection来提高安全性和性能吗?

简而言之,每次都可以使用通用集合。