两次使用C#迭代器意外地工作

时间:2014-06-27 08:53:16

标签: c# linq iterator

这是我第一次使用C#编写代码 - 我有C / Python / Javascript / Haskell的背景知识。

为什么下面的程序有效?我希望这可以在Haskell中工作,因为列表是不可变的,但我正在努力学习如何使用相同的迭代器nums两次,没有错误。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            var nums = new List<int?>() { 0, 0, 2, 3, 3, 3, 4 };
            var lastNums = new List<int?>() { null } .Concat(nums);
            var changesAndNulls = lastNums.Zip(nums,
                (last, curr) => (last == null || last != curr) ? curr : null
            );
            var changes = from changeOrNull in changesAndNulls where changeOrNull != null select changeOrNull;

            foreach (var change in changes) {
              Console.WriteLine("change: " + change);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:4)

在您的代码中nums不是IEnumerator<T>(迭代器),IEnumarable<T>IEnumarable <T>具有GetEnumerator()方法,可以作为许多方式调用时间根据需要:

IEnumerable<int?> nums = new List<int?>() { 0, 0, 2, 3, 3, 3, 4 };

// Linq gets enumerator to do Concat 
using (var iterator1 = nums.GetEnumerator()) {
   while (iterator1.MoveNext()) {
     ...
   }
}

...

// Linq gets (fresh!) enumerator to do Zip 
using (var iterator2 = nums.GetEnumerator()) {
   while (iterator2.MoveNext()) {
    ...
   }
} 

因此IEnumerable<T>工厂生成IEnumerator<T>个实例(并且IEnumerator<T>无法重复使用

答案 1 :(得分:2)

List<int?>实现接口IEnumerable<int?>。这意味着它有一个名为GetEnumerator()的方法。 此方法返回一个新的Enumerator<int?>对象,用于迭代所有项目。

当你在foreach循环中使用它时,或者当你调用GetEnumerator()之类的许多扩展方法之一(自己调用Concat())时,你正在调用GetEnumerator()(在后台)

我建议您学习C#教程。它是一种与Haskell截然不同的语言,它具有一些非常独特的功能。 仅限初学者:http://en.wikipedia.org/wiki/C_Sharp_syntax