2次元の List (foreach, LINQ 使用可)

System.Collections.Generic.List<T> の2次元版みたいなクラスが欲しくなり自作しました。

### 要件
- 2次元配列っぽく [x, y] で値を参照・代入可能
- foreach 使いたい。 foreach の中で値を変更したい
- LINQ で範囲操作したい

# コード

コード全文を載せます。 List2D クラスと、 foreach 及び LINQ を使うための List2dIterator<T>, List2dIndexer<T> というクラスが含まれています。

```csharp:List2D.cs
using System.Linq;

namespace System.Collections.Generic
{
	public class List2D<T> : IEnumerable<List2dIndexer<T>> where T : new()
	{
		public List2D(int w, int h)
		{
			mWidth = w;
			mHeight = h;

			mArr = new List<T>(w * h);

			foreach (int i in Enumerable.Range(1, w * h))
			{
				mArr.Add(new T());
			}
		}

		public T get(int x, int y) { return mArr[x + y * mWidth]; }
		public void set(int x, int y, T val) { mArr[x + y * mWidth] = val; }

		public T this[int x, int y]
		{
			set { mArr[x + y * mWidth] = value; }
			get { return mArr[x + y * mWidth]; }
		}

		public int Count { get { return mWidth * mHeight; } }
		public int Width { get { return mWidth; } }
		public int Height { get { return mHeight; } }

		public List2dIterator<T> GetEnumerator()
		{
			return new List2dIterator<T>(this);
		}

		IEnumerator<List2dIndexer<T>> IEnumerable<List2dIndexer<T>>.GetEnumerator()
		{
			return GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		protected int mWidth;
		protected int mHeight;
		protected List<T> mArr;
	}

	public class List2dIterator<T> : IEnumerator<List2dIndexer<T>> where T : new()
	{
		public List2dIterator(List2D<T> lst)
		{
			indexer = new List2dIndexer<T>();
			indexer.x = -1;
			indexer.y = 0;
			indexer.container = lst;
		}

		public List2dIndexer<T> Current
		{
			get
			{
				return indexer;
			}
		}

		object IEnumerator.Current
		{
			get
			{
				return Current;
			}
		}

		public void Dispose() { }

		public bool MoveNext()
		{
			++indexer.x;
			if (indexer.x == indexer.container.Width)
			{
				indexer.x = 0;
				indexer.y++;
			}
			return (indexer.y != indexer.container.Height);
		}

		public void Reset()
		{
			indexer.x = -1;
			indexer.y = 0;
		}

		List2dIndexer<T> indexer;
	}

	public class List2dIndexer<T> where T : new()
	{
		public T Value { get { return container[x, y]; } set { container[x, y] = value; } }

		public int X { get { return x; } }
		public int Y { get { return y; } }

		public bool isLastCol { get { return x == container.Width - 1; } }

		internal List2D<T> container;
		internal int x;
		internal int y;
	}
}
```

# 使用例

```csharp:main.cs
using System;
using System.Collections.Generic;
using System.Linq;

public class Test
{
	public static void Main()
	{
        // 幅 20, 高さ 20 の2次元 List 作成
		var list = new List2D<int>(20, 20);

        // 中心座標 (10.0, 10.0) から距離 5 以内の点を抽出
		var query = from i in list
					where (10.0 - i.X) * (10.0 - i.X) + (10.0 - i.Y) * (10.0 - i.Y) <= 25
					select i;

        // クエリで抽出した点に 1 を代入
        // i の型は List2dIndexer<int>
		foreach(var i in query) { i.Value = 1; }

        // コンソール出力
		foreach(var i in list)
		{
			Console.Write(i.Value == 1 ? "*" : ".");

			if(i.isLastCol)
			{   // 行末で改行
				Console.WriteLine("");
			}
		}
	}
}
```

```text:コンソール出力
....................
....................
....................
....................
....................
..........*.........
.......*******......
......*********.....
......*********.....
......*********.....
.....***********....
......*********.....
......*********.....
......*********.....
.......*******......
..........*.........
....................
....................
....................
....................
```

2次元データに対して LINQ の範囲操作ができるとコードが直感的に読めとても便利です。