IEnumrableが使えば使うほど楽しいです。
例としてマインスイーパーを作るとします。
class Cell{
public bool isMine();
}
class Field{
public Cell GetCell(int x, int y){
if (x < 0 || maxx <= x) return null;
if (y < 0 || maxx <= y) return null;
return cell[x,y];
}
}
GetCellでセルクラスを取得できますが、範囲外を取得しようとするとnullを返します。
isMine()は爆弾がセルにあればtrue,なければfalseを返します。
こういうとき、周りの8マスを調べて爆弾の値をとりたい、と考えるとどう書けばいいでしょうか。
class Field{
public IEnumrable<Cell> Get8Round(int x, int y){
yield return GetCell(x - 1, y - 1);
yield return GetCell(x , y - 1);
yield return GetCell(x + 1, y - 1);
yield return GetCell(x - 1, y );
yield return GetCell(x + 1, y );
yield return GetCell(x - 1, y + 1);
yield return GetCell(x , y + 1);
yield return GetCell(x + 1, y + 1);
}
public int GetMineNum(int x, int y){
return Get8Round(x, y).Count(l => l != null && l.isMine());
}
}
今回の肝は8近傍を返す関数というところにあります。
中身は泥臭い方法で実装していますが、一度作ってしまえばこれを使いまわせます。
周り8マスの集合を作り、nullでなくてisMine()がtrueの個数、という風に
頭で思いついた通りに打つだけでその通りにできるうえ、
インデックスやカウンター用の変数が出てこなくて済む、というのはありがたいです。
考えてみれば、for文を絡む部分はモジュール化しにくい部分でした。
8近傍を取る部分が出てくるたびにどこかにあるforをコピペして使っていました。
また、そのためにoffsetx[8], offsety[8]というものをグローバル領域に取ったりもしていました。
正直、for文というのは可読性がよくないように思います。
yieldを使えば簡単にモジュール化できるうえ、IEnumrableに便利な関数が増えているので、
for文をあまり使わないコーディングスタイルもありではないでしょうか。