コンピュータなんてものは詰まるところ、条件分岐とgotoの塊なんです。決められたとおりにしか動きませんし、決められたことなら何でもできます。プログラミング言語ではif, while(for)が使えればつまるところ何でもできますが、それはとても見づらいプログラムなんですね。
例えばコントローラーを操作するプログラムを考えましょう。 コントローラーの値を取得するために、for文で取得するとします。
for(int i = 0; i < controller_number; i++) { state = controller[i].getState(); for(int j = 0; j < state.button_number; j++) { if((state.button[j] & 0x80) == 0x80) { controller[i].inputButton(j); } } }controllerはControllerクラスの配列で、そのサイズがcontroller_numberで取得できているとします。 続いて、stateはcontrollerのメソッドgetStateで取得した値で、ボタンのON/OFFやアナログスティックの値を記録しています。これはDirectInputを想定しています。 ボタンが押されたら、0x80でマスクしてそれが0x80と一致するかどうかチェックして、一致していたらコントローラーのボタンメソッドを呼び出します。
もちろんこれはこれでいいのですが、このようなコードは冗長だと思いませんか。 毎回毎回おきまりのint i = 0してi++とおきまりのコードを書く。 ぱっと見、このループが特別な処理のためのループなのか、ある配列などを反復して処理しているだけなのか分かりません。
もしもC#のforeachを使って次のように書けたら幸せでしょう。
foreach(Controller controller in controllers) { // iがない foreach(State.Button state_button in controller.getState().getButton()) { // このState.Buttonは実質byteである if((state_button & 0x80) == 0x80) { controller.inputButton(j); } } }iとかjとかあるコードよりもぱっと見て反復していることが分かりよいでしょう。 また、iとかjとかに悩まされることもありません。
それでは自分で実装してみましょう。foreachを使うには、foreach用に System.Collections.IEnumerableインターフェースを実装する必要があります。 IEnumerableは public System.Collections.IEnumerator GetEnumerator() を実装すれば良いです。これはforeach(★ in ●)の(●)にあたるオブジェクトのIFです。 IEnumeratorは状態をリセットするpublic void Reset()と、 次へ進むpublic bool MoveNext()。ただし繰り返すときだけtrueを返す。 そして現在の状態(★)を返すobject System.Collections.IEnumerator.Currentプロパティが必要です。
次の例ではMyClassにあるプロパティary (int型配列)をクラスそのものを使ってforeachで取得できるようにしたものです。
using System.Timers; class Program { public static void Main() { MyClass myclass = new MyClass(); myclass.setSeriesData(); foreach(int x in myclass) { System.Console.WriteLine("{0}", x); } } } class MyClass : System.Collections.IEnumerable { int[] ary; const int MAX_SIZE = 32; public MyClass() { ary = new int[MAX_SIZE]; } public void setSeriesData(){ for(int i = 0; i < MAX_SIZE; i++) { ary[i] = i; } } public System.Collections.IEnumerator GetEnumerator() { return new MyClassEnum(this); } class MyClassEnum : System.Collections.IEnumerator { int current; MyClass myclass; public MyClassEnum(MyClass myclass) { this.myclass = myclass; } object System.Collections.IEnumerator.Current { get { return myclass.ary[current]; } } public void Reset() { current = 0; } public bool MoveNext() { current++; return current < MyClass.MAX_SIZE; } } }
0 件のコメント:
コメントを投稿