ITコンサルの日常

ITコンサル会社に勤務する普通のITエンジニアの日常です。

IEnumerable(オブジェクトをforeachできるようにする)

プログラミングC# p207

さっきのRectangleをEnumerableにしてみる。
順番にxとyを返すというもの。

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

class Rectangle : IEnumerable
{
        private int x;
        private int y;

        public Rectangle(int x, int y)
        {
                this.x = x;
                this.y = y;
        }

        public IEnumerator GetEnumerator()
        {
                yield return x;
                yield return y;
        }

        static void Main(string[] args)
        {
                Rectangle r = new Rectangle(4, 5);
                foreach(int i in r)
                {
                        Console.WriteLine("i = {0}", i);
                }
        }
}

結果はこう。

i = 4
i = 5

「using System.Collections;」を抜かすとこんなエラーが出る。

IEnumerableTest.cs(5,19): error CS0305: ジェネリック 型
        'System.Collections.Generic.IEnumerable' の使用には、'1'
        型の引数が必要です。
c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll:
        (以前のエラーに関連するシンボルの位置)
IEnumerableTest.cs(16,9): error CS0305: ジェネリック 型
        'System.Collections.Generic.IEnumerator' の使用には、'1'
        型の引数が必要です。
c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll:
        (以前のエラーに関連するシンボルの位置)

ちょっとはまった。。


ちなみにRuby

class Rectangle
        def initialize(x, y)
                @x = x;
                @y = y;
        end

        def each()
                yield @x;
                yield @y;
        end
end

r = Rectangle.new(4, 5)

r.each { |i|
        print "i = #{i}\n"
}

結果はこう。

i = 4
i = 5

Enumerableをincludeすると、さらに色々できるようになるらしい。


そういやJava。Enumerableというか、拡張for文で使うことの出来るオブジェクトの要件ってなんなんだろう?
Javaのドキュメントからたどり、JSR201を経由して、Java Language Specification Third Editionにたどり着きました。
http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.14.2
これによると、

The Expression must either have type Iterable or else it must be of an array type (§10.1), or a compile-time error occurs.

で、java.lang.Iterableを実装するか配列であればOKらしい。
早速Rectangle.javaを実装してみる。

import java.util.*;

public class Rectangle implements Iterable
{
        private int x;
        private int y;

        public Rectangle(int x, int y)
        {
                this.x = x;
                this.y = y;
        }

        public Iterator iterator()
        {
                return new Iterator() {
                        private int count = 0;

                        public boolean hasNext()
                        {
                                if(count < 2)
                                {
                                        return true;
                                }
                                else
                                {
                                        return false;
                                }
                        }

                        public Object next()
                        {
                                switch(count)
                                {
                                        case 0:
                                                count++;
                                                return new Integer(x);
                                        case 1:
                                                count++;
                                                return new Integer(y);
                                        default:
                                                return null;
                                }
                        }

                        public void remove()
                        {
                        }
                };
        }

        public static void main(String[] args)
        {
                Rectangle r = new Rectangle(4, 5);
                for(Object o : r)
                {
                        System.out.println(o);
                }
        }
}

う〜ん。ちょっと手軽さに欠けますね。
使うほうは簡単だが、作る方は手間がかかると。
ちなみに結果はこう。

4
5