有关IEnumerable和IEnumerator的问题

问题描述 投票:7回答:7

我使用以下代码使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
c# .net ienumerable ienumerator
7个回答
11
投票

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将该类型为字符串,而不是通过强制转换指示编译器为字符串。


6
投票

1)IEnumerator的作用是什么? IEnumeratorIEnumerable有什么区别?

IEnumerator是一个接口,表示可以枚举序列的方法。 IEnumeratorIEnumerable的区别在于,前者表示允许您枚举序列的对象的协定,而后者表示可以被枚举的序列的对象的协定。

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的实例不能。


3
投票

这是IEnumerable<T>的声明:

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

您别无选择,您也要实现非通用IEnumerable接口。如果省略IEnumerable.GetEnumerator()实现,则会出现编译错误。这是.NET 1.x日子遗留下的行李,当时尚无法使用泛型,而.NET 2.0的过渡期则需要支持与.NET 1.x程序集的互操作。我们坚持下去。


3
投票

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

0
投票

[GetEnumerator自从将泛型引入语言以来就已经存在,为了不破坏已有的代码,默认方法会调用泛型实现。

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


0
投票

关于第三个问题(为什么要使用泛型?),一些答案:

Should we use Generic Collection to improve safety and performance?

简而言之,请尽可能使用通用集合。


0
投票

要了解差异,您需要了解其用法。实际上,它们表示Iterator设计模式,它是面向对象的软件开发人员使用的设计模式之一。

迭代器模式提供了一种顺序访问集合元素的方式,而无需知道集合的结构。

在传统的设计模式方法中,迭代器模式具有用于创建Iterator对象的Aggregate接口和用于遍历Aggregate对象的Iterator接口。

现在,IEnumerable充当保证返回迭代器的Aggregate接口。迭代器(也称为枚举器)负责按某些条件定义的顺序生成下一个元素。 IEnumerator是定义此功能的接口。您可以在我的博客文章Iterator Pattern C#中了解有关此模式的更多信息>

© www.soinside.com 2019 - 2024. All rights reserved.