【问题标题】:Double-use of C# iterator works unexpectedly双重使用 C# 迭代器意外工作
【发布时间】:2014-06-27 08:53:15
【问题描述】:

这是我第一次使用 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);
            }
        }
    }
}

【问题讨论】:

  • 哪一行代码以意想不到的方式工作?
  • 双重用途在哪里?
  • nums 不是IEnumerator&lt;T&gt;,它是IEnumerable&lt;T&gt;',它有GetEnumerator() 方法来调用任意时间
  • @AdamHouldsworth numslastNums 都作为迭代器访问 nums,并在 Zip 中并行使用。
  • @chrisdew nums 不是一个“迭代器”,它是一个“可迭代的”集合,只是被迭代两次,这是允许的,因为遍历它的每个迭代器都是自己独立的状态机。

标签: c# linq iterator


【解决方案1】:

在您的代码中,nums 不是 IEnumerator&lt;T&gt;(迭代器),它是 IEnumarable&lt;T&gt;IEnumarable &lt;T&gt; 具有 GetEnumerator() 方法,可以根据需要多次调用: p>

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&lt;T&gt; 是一个工厂 生产IEnumerator&lt;T&gt; 实例(它是一个IEnumerator&lt;T&gt; 不能重复使用

【讨论】:

  • 它与问题并不真正相关,也没有人使用过此功能,但IEnumerator&lt;T&gt; 可以通过调用Reset() 重复使用。 (虽然它在这里不起作用,因为枚举器的两种用途是并行的。)
【解决方案2】:

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

当您在 foreach 循环中使用 GetEnumerator() 或调用许多扩展方法之一时,您正在调用 GetEnumerator()(在后台),例如 Concat()(它们自己调用 GetEnumerator())。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-15
    • 1970-01-01
    • 2013-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多