ようやくLINQについて書けるときが来ました。ここまで長かった。。。地味な変更が続いたのでインパクトのあるやつをやりましょう。
では、いつものようにdefault.aspx.csを開いて、void Page_Load(object sender, EventArgs e) メソッドにカーソルを移動してください。このメソッドにはまだ修正を加えていないので、オリジナルのコードが
protected void Page_Load(object sender, EventArgs e)
{
List<Product> products = GetProductList();
GridView1.DataSource = products;
GridView1.DataBind();
}
あるはずです。では、products のデータをグループに分けてそのグループのレコードの数を計算するコードをC#2.0を使って実装してみます。
まず、グループのコンテナクラスを追加します - Demo 名前空間のどこかに以下のコードをコピーしてください。
class Grouping
{
int productCount;
int categoryID;
public int ProductCount
{
get { return productCount; }
set { productCount = value; }
}
public int CategoryID
{
get { return categoryID; }
set { categoryID = value; }
}
}
次に、実際にグループ化するロジックを Page_Load メソッドの中に追加。
protected void Page_Load(object sender, EventArgs e)
{
List<Product> products = GetProductList();
Dictionary<int, Grouping> groups = new Dictionary<int, Grouping>();
foreach (Product p in products)
{
if (!groups.ContainsKey(p.CategoryID))
{
Grouping r = new Grouping();
r.CategoryID = p.CategoryID;
r.ProductCount = 0;
groups.Add(r.CategoryID, r);
}
groups[p.CategoryID].ProductCount++;
}
List<Grouping> result = new List<Grouping>(groups.Values);
GridView1.DataSource = result;
GridView1.DataBind();
}
ここまでのコードをミスなく書ける人はそれなりにいるかもしれません。では、さらにソートを追加してみましょう。
…
…
List<Grouping> result = new List<Grouping>(groups.Values);
result.Sort(delegate(Grouping x, Grouping y)
{
return
x.ProductCount > y.ProductCount ? -1 :
x.ProductCount == y.ProductCount ? 1 :
0;
}
);
GridView1.DataSource = result;
…
…
ここまで一つのバグを入れることなく書けた人はすばらしい。でも、本人が書けたとしてもそれをほかの人が読んですぐ理解できるかというと?です。
そこで、LINQの登場です。結論から言うと、LINQを使ったコードは
protected void Page_Load(object sender, EventArgs e)
{
List<Product> products = GetProductList();
var result = from p in products
group p by p.CategoryID into g
orderby g.Count() descending
select new
{
CategoryID = g.Key,
Count = g.Count()
};
GridView1.DataSource = result;
GridView1.DataBind();
}
しかも、さきほど追加したグループのコンテナクラスは不要です。比べていただくを分かりやすいのでC# 2.0 Based は
protected void Page_Load(object sender, EventArgs e)
{
List<Product> products = GetProductList();
Dictionary<int, Grouping> groups = new Dictionary<int, Grouping>();
foreach (Product p in products)
{
if (!groups.ContainsKey(p.CategoryID))
{
Grouping r = new Grouping();
r.CategoryID = p.CategoryID;
r.ProductCount = 0;
groups.Add(r.CategoryID, r);
}
groups[p.CategoryID].ProductCount++;
}
List<Grouping> result = new List<Grouping>(groups.Values);
result.Sort(delegate(Grouping x, Grouping y)
{
return
x.ProductCount > y.ProductCount ? -1 :
x.ProductCount == y.ProductCount ? 1 :
0;
}
);
GridView1.DataSource = result;
GridView1.DataBind();
}
これがLINQとC# 3.0 の本質つまりPPT のP7 の2つ目のポイント
手続き型 à 論理型
の具体的な例です。関数型言語は当たり前の、Developer がどうするのか、つまりHow に時間を使うことなく何をしたいのか、つまり What に集中することが LINQ と C#3.0 を使っていただくとできるようになります。
あすは、Deep に掘り下げてきた LINQ + C# 3.0 を横に広げて Linq Family を使って色々な data source にクエリをかけてみたいと思います。