yield return では Reset() できない


yield return で、Reset() しようとしたら、例外が発生したので、メモ。

yield return を使って、1つづつ値を処理しようと思ったのですが、一般には次のような foreach, IEnumerator を使って、列挙することができます。

using System;
using System.Collections.Generic;
using System.Collections;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass mc = new MyClass();

            foreach (string s in mc)
                Console.WriteLine(s);

            IEnumerator<string> e = mc.GetEnumerator();
            while (e.MoveNext())
            {
                Console.WriteLine(e.Current);
            }            Console.ReadLine();
        }

        public class MyClass
        {
            public IEnumerator<string> GetEnumerator()
            {
                yield return “Hello1”;
                yield return “Hello2”;
                yield return “Hello3”;
                yield return “Hello4”;
            }
        }
    }
}

ある限られた要素を、無限に Enumerate できるようにしようと思って、yield return で与えられた Enumerable を Enumerate して、MoveNext()できなかったら、最初にReset()したが、Reset()のところで、NotSupportedException 例外となりました。

IEnumerator<string> col = mc.GetEnumerator();

for (int i = 0; i < 50; i++)
{
    if (col.MoveNext() == false)
    {
        col.Reset();   // <<<<<<<<<<<<<< ここで NotSupportedException 例外
        col.MoveNext();
    }
    Console.WriteLine(col.Current);
}

aetos さんのところに詳細に解説が載ってました。http://blogs.wankuma.com/shannon/archive/2007/07/10/84596.aspx

yield は Reset() のところまで実装していないので、当然リセットできないということですね。なお、これを回避するには、Reset()ではなく、Enumerator を取り直せば、繰り返しできる。

ある限られた要素を、無限に列挙するのは、あえてやるとすると、こんな感じ?

MyClass2 mc2 = new MyClass2();

for (int i = 0; i < 50; i++)
{
    Console.WriteLine(mc2.GetNext());
}

public class MyClass2
{
    string[] test = { “Hello1”, “Hello2”, “Hello3”, “Hello4”, “Hello5” };
    static int i = -1;
    public string GetNext()
    {
        if (++i >= test.Length)
            i = 0;
        return test[i];
    }
}

neueccさんからの linq のコードを教えてもらった。なるほど~。有限回の繰り返しなら、シンプルでいいねー。

http://gyazo.com/6c17ca767c84e4f695a3f4420a66dba2

var array = new[] { “Hello1”, “Hello2” };
var query = Enumerable.Repeat(array, 2).SelectMany(xs=>xs);

foreach(var item in query)
    Console.WriteLine(item);

コメントを残す