.net中的IEnumerable是什么


68

.net中的IEnumerable是什么?


26
老实说,对于MSDN的定义对于初学者来说非常令人恐惧,因为您要做的只是学习。
SWeko 2010年

11
尽管我可以理解为什么关闭了它,但在MSDN不清楚之后,我还是从Google那里获得了答案,答案确实对我有所帮助。如果可以的话,我将投票赞成重新开放。...当谷歌搜索“什么是IEnumerable”时,这一点很高,我相信其他人会发现它很有帮助。
维尔

Answers:


71

这是……您可以循环播放的东西。那可能是一个List或一个Array或(几乎)其他任何支持foreach循环的东西。它用于您希望能够使用带有foreach循环的对象,但又不知道要处理的类型是数组,列表还是自定义类型。

这就是那里的第一个优点:如果您的方法接受IEnumerable而不是数组或列表,则它们将变得更强大,因为您可以向它们传递更多不同类型的对象。

现在,使IEnumerable真正脱颖而出的是迭代器块(yieldC#中的关键字)。迭代器块像列表或数组一样实现IEnumerable接口,但它们非常特殊,因为与列表或数组不同,它们通常一次只保存单个项目的状态。因此,例如,如果要在一个非常大的文件中循环,可以编写一个迭代器块来处理文件输入。这样一来,您一次存储的文件就永远不会超过一行,而且如果您更早完成循环(也许是搜索并找到了所需的内容),则可能不需要读取整个文件。或者,如果您正在从大型SQL查询中读取结果,则可以将内存使用限制为一条记录。

另一个功能是此评估是惰性的,因此,如果您正在做复杂的工作来评估可读取的可枚举对象,那么直到需要它时,该工作才会发生。这是额外的好处,因为经常(例如,再次进行搜索)您可能会发现根本不需要进行这项工作。

您可以将IEnumerable视为即时列表。


1
关键IEnumarable在于,not enumerated直到特别扩展支持集合为止,无论是通过索引器进行的foreach还是访问器。不幸的是,IEnumarable似乎被盲目地用作了最低的接口,现在它导致异步数据操作(例如,在GarbageCollected上下文上执行SQL)的问题。我要说的ICollection是,除了“惰性评估”外,您所说的都是每件事,我们应该使用它,特别是如果数据已经被枚举一次!
皮奥特库拉(Piotr Kula)

1
用简单的英语最好的简单解释,谨防!
Jeb50 '18

我认为IEnumerable的名字不好用。在数学上和计算中,可枚举是映射到可数集的任何事物。因此,在.net之外,IObservable可能是枚举的。在.NET中,IEnumerable在拉对推对偶性中被视为IObservable的对立面。IEnumerable的意图似乎是Java所谓的Iterable,在我看来,这是一个更好的名称。
Sentinel

34

这是由.NET中的Collection类型实现的接口,该类型提供Iterator模式。也有通用版本IEnumerable<T>

在实现IEnumerable的集合中移动的语法(您很少看到,因为有做起来更漂亮的方法)是:

IEnumerator enumerator = collection.GetEnumerator();

while(enumerator.MoveNext())
{
    object obj = enumerator.Current;
    // work with the object
}

在功能上等效于:

foreach(object obj in collection)
{
    // work with the object
}

如果该集合支持索引器,那么您也可以使用经典的for循环方法对其进行迭代,但是Iterator模式提供了一些不错的功能,例如为线程添加同步的功能。


注意,这里显示的语法取决于foreach的C#5。在C#4和更早的版本object obj;中,在循环之外声明了,这在处理捕获变量(如匿名函数)的事物时会改变循环的行为。
斯科特·张伯伦

技术对技术的回答只会带来更多的困惑和挫败感。
Jeb50 '18 -4-8

13

首先,它是一个接口。根据MSDN的定义是

公开枚举器,该枚举器支持对非泛型集合的简单迭代。

简单地说,实现此接口的任何对象都将提供一种获取枚举数的方法。一个枚举器用作foreach示例。

列表实现IEnumerable接口。

    // This is a collection that eventually we will use an Enumertor to loop through
    // rather than a typical index number if we used a for loop.
    List<string> dinosaurs = new List<string>();

    dinosaurs.Add("Tyrannosaurus");
    dinosaurs.Add("Amargasaurus");
    dinosaurs.Add("Mamenchisaurus");
    dinosaurs.Add("Deinonychus");
    dinosaurs.Add("Compsognathus");

    Console.WriteLine();

    // HERE is where the Enumerator is gotten from the List<string> object
    foreach(string dinosaur in dinosaurs)
    {
        Console.WriteLine(dinosaur);
    }

    // You could do a 
    for(int i = 0; i < dinosaurs.Count; i++)
    {
        string dinosaur = dinosaurs[i];

        Console.WriteLine(dinosaur);
    }

foreach看起来更干净。


7

简短的答案是,您可以在foreachon上使用它。


4
您可以使用GetEnumerator方法遍历所有内容。它不必支持IEnumerable。
Joel Coehoorn 2010年

是的,但大部分的时间IEnumerable <==> foreach
SWeko

0
  • 它是一个基本接口,使我们可以循环或遍历Collection。

  • 关于IEnumerable的最重要说明是,当您遍历一个对象或集合时,它一次仅保存单个项目的状态。

  • 当您遍历大对象或集合时,它具有良好的性能,因为它不会将整个对象加载到内存中以进行迭代。例如,假设您决定逐行读取一个大文件并对其进行处理,因此可以编写自己的ReaderEnumrable来高性能读取文件。

  • 当您使用IEnumerable编写查询时,您将利用延迟执行和查询访问后运行的优点。

  • 每次运行时,您都会遍历一个集合,从而创建另一个集合。例如,在以下代码中,每次被listOfFiles访问时ListOfAllFiles再次执行。

    public static void Main()
    {
        var listOfFiles = ListOfAllFiles();
    
        var filesCount = listOfFiles.Count();
        var filesAny = listOfFiles.Any();
        var fileIterate = listOfFiles.Select(x => x.FullName);
    }
    
    private static IEnumerable<FileInfo> ListOfAllFiles()
    {
        foreach(var file in Directory.EnumerateFiles(Environment.CurrentDirectory))
        {
            yield return new FileInfo(file);
        }
    }
    

您的大多数假设都是“收益率回报”的特征,而不是IEnumerable。IEnumerable只是提供迭代方式的接口,仅此而已。
瓦西里·oreshenski

您在使用yield return 时正在使用IEnumerable,因此它们是完全相关的。
Seyedraouf Modarresi '02
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.