我使用以下代码使myClass可以使用foreach。但是我对编程还是比较陌生,在理解以下代码方面有些困难。我在评论中描述了我的问题。我将不胜感激提供一些信息。
public class MyClass : IEnumerable<string>
{
//1) What is IEnumerator for?
// Whats the difference between IEnumerator and IEnumerable
public IEnumerator<string> 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<string> instead of just IEnumerable
IEnumerator和IEnumerable有什么区别?
Jason的回答很好,但我想我只是添加我对此的看法。假设您有一个序列:
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转换为对象,将整数装箱,然后立即将对象取消装箱成整数,从而为每个操作添加完全不必要的内存分配。如果编译器知道序列是整数,则可以跳过不必要的装箱操作。
假设序列是字符串。如果实现IEnumerable<string>
,则可以说:
string first = mysequence.First();
如果没有,那么你不得不说
string first = (string)mysequence.First();
这是不必要的,容易出错。您可以通过使用类型系统简单地guarantee将该类型为字符串,而不是通过强制转换指示编译器为字符串。
1)
IEnumerator
的作用是什么?IEnumerator
和IEnumerable
有什么区别?
IEnumerator
是一个接口,表示可以枚举序列的方法。 IEnumerator
和IEnumerable
的区别在于,前者表示允许您枚举序列的对象的协定,而后者表示可以被枚举的序列的对象的协定。
public IEnumerator<string> GetEnumerator() {
yield return "first";
yield return "second";
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
2)它是做什么用的?它只是调用上述方法。
前者表示合同GetEnumerator
上方法IEnumerable<string>
的实现。后者表示对合同GetEnumerator
的方法IEnumerable
的明确实现。问题在于,两个合同都有一个名为GetEnumerator
的方法,但返回类型不同,因此一个方法不能同时满足两个合同(任何实现IEnumerable<T>
的类也必须将IEnumerable
实现为IEnumerable<T> : IEnumerable
)。后者调用IEnumerable<string>.GetEnumerator
的实现,因为这是一个明智的实现,它返回IEnumerator
作为IEnumerator<string> : IEnumerator
。
3)最后,从实现通用接口
IEnumerable<string>
而不仅仅是IEnumerable
有什么好处?
强力打字。您知道序列IEnumerable<string>
中的元素都是String
的所有实例,但是您不知道IEnumerable
的元素,并且最终可能试图将后者的元素转换为String
的实例不能。
这是IEnumerable<T>
的声明:
public interface IEnumerable<out T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
您别无选择,您已也要实现非通用IEnumerable接口。如果省略IEnumerable.GetEnumerator()实现,则会出现编译错误。这是.NET 1.x日子遗留下的行李,当时尚无法使用泛型,而.NET 2.0的过渡期则需要支持与.NET 1.x程序集的互操作。我们坚持下去。
1)IEnumerator的作用是什么?
IEnumerator是带有MoveNext()和Current成员的实际工作部分。
[IEnumerator和IEnumerable之间有什么区别
IEnumerable是集合的接口,以表示其具有GetEnumerator()。
2)[非通用GetEnumerator]的作用是什么?它只是调用上面的方法
非通用方法只是为了向后兼容。注意,通过使用显式实现,它尽可能地“移开”。实施它,因为您必须先忘记它。
3)最后,我从实现基因接口中有什么好处IEnumerable而不是IEnumerable
与foreach
一起使用时,优势很小,因为foreach将强制转换循环变量。它会让您在foreach中使用var
:
foreach (var s in myClassInstance) // needs `IEnumerable<string>`
foreach (string s in myClassInstance) // works with `IEnumerable` as well
但是使用IEnumerable<string>
,您还具有到其他区域的类型安全接口,最著名的是LINQ:
MyClass mc = new MyClass ();
string s = mc.FirstOrDefault();
[GetEnumerator
自从将泛型引入语言以来就已经存在,为了不破坏已有的代码,默认方法会调用泛型实现。
使用通用枚举,您的类的使用者在迭代时不需要将每个项目都转换为字符串。
关于第三个问题(为什么要使用泛型?),一些答案:
Should we use Generic Collection to improve safety and performance?
简而言之,请尽可能使用通用集合。
要了解差异,您需要了解其用法。实际上,它们表示Iterator设计模式,它是面向对象的软件开发人员使用的设计模式之一。
迭代器模式提供了一种顺序访问集合元素的方式,而无需知道集合的结构。
在传统的设计模式方法中,迭代器模式具有用于创建Iterator对象的Aggregate接口和用于遍历Aggregate对象的Iterator接口。
现在,IEnumerable充当保证返回迭代器的Aggregate接口。迭代器(也称为枚举器)负责按某些条件定义的顺序生成下一个元素。 IEnumerator是定义此功能的接口。您可以在我的博客文章Iterator Pattern C#中了解有关此模式的更多信息>