人気ブログランキング | 話題のタグを見る
(.Net)LINQのクエリ構文とメソッド構文(ラムダ式)を使ってみた
.Net Framework 3.5(C#3.0)から追加されたLINQですが、ようやく使ってみることにしました。

SQLServer等のDBへの問い合わせに使えるようですが、今回はコレクションでの検索がメインです。

とりあえず基本的なことは、@IT:LINQ(リンク)の基礎知識と、VB はじめてのLINQ - LINQ, From, Where, Select, OfTypeで頭に詰め込みます。

単純なコレクション検索だと下記のような感じになります。

public partial class Form1 : Form {
private void button1_Click(object sender, EventArgs e) {
//テスト用のデータ生成
List<TestClass> lst = new List<TestClass>();
lst.Add(new TestClass() { Name = "a", Id = 1 });
lst.Add(new TestClass() { Name = "b", Id = 2 });
lst.Add(new TestClass() { Name = "c", Id = 3 });
lst.Add(new TestClass() { Name = "d", Id = 5 });
lst.Add(new TestClass() { Name = "e", Id = 5 });
lst.Add(new TestClass() { Name = "f", Id = 4 });
lst.Add(new TestClass() { Name = "g", Id = 5 });
 
//LINQで検索 IDが5のものを探す
var query = from res in lst
where res.Id == 5
select res; //今回は TestClass オブジェクトを返すが、res.Name とかすることも可能
//foreach句で結果が参照できる
foreach (var res in query)
{
Console.WriteLine(res.Name + " , " + res.Id);
}
}
}
 
 
public class TestClass {
public string Name { get; set; }
public int Id { get; set; }
}

from in 句で検索元データを指定し、where で条件、select で結果として欲しいオブジェクトを指定します。
SQLチックで簡単にデータ抽出できますね。


しかし、いざ実用しようかと思うと、問題になったのがクエリの条件が動的になる場合です。
SQLだと string 結合するだけでよかったんですが、上記のようなLINQの書き方では動的には条件設定ができません。

LINQを活用した簡単XMLデータベース・アプリケーションにて、動的に条件を設定する方法が書いてあるんですが、ラムダ式やら式ツリーやらいまいちわかりません。


ということでLINQ 超入門(4) クエリの文法 where句 - 気楽なC#工房を参考にしました。

実際の条件に一致するかどうかのフィルタ部分を別メソッドに持たせる方法です。
こんな感じです。

public partial class Form1 : Form {
private void button1_Click(object sender, EventArgs e) {
//テスト用のデータ生成
List<TestClass> lst = new List<TestClass>();
lst.Add(new TestClass() { Name = "a", Id = 1 });
lst.Add(new TestClass() { Name = "b", Id = 2 });
lst.Add(new TestClass() { Name = "c", Id = 3 });
lst.Add(new TestClass() { Name = "d", Id = 5 });
lst.Add(new TestClass() { Name = "e", Id = 5 });
lst.Add(new TestClass() { Name = "f", Id = 4 });
lst.Add(new TestClass() { Name = "g", Id = 5 });
 
//LINQで検索 IDが5のものを探す
var query = from res in lst
where Filter(res,null,5)
select res;
//foreach句で結果が参照できる
foreach (var res in query) {
Console.WriteLine(res.Name + " , " + res.Id);
}
}
 
//実際に条件を判定するメソッド。引数がnullでない時にチェックする。
private bool Filter(TestClass cls, string filterName, int? filterId) {
if (filterName != null && !cls.Name.Contains(filterName)){
return false;
}
if (filterId.HasValue && cls.Id != filterId.Value) {
return false;
}
return true;
}
}
 
public class TestClass {
public string Name { get; set; }
public int Id { get; set; }
}

ただ上記の Filter メソッドの場合、条件がANDだけになってしまいます。
OR条件にするは Filter メソッドを下記のようにします。

private bool Filter(TestClass cls, string filterName, int? filterId) {
if (filterName != null && cls.Name.Contains(filterName)) {
return true;
}
if (filterId.HasValue && cls.Id == filterId.Value) {
return true;
}
return false;
}

ただ複雑な条件は指定できないので、やはりラムダ式で式ツリーを生成する方法じゃないとダメでしょうかね。。。


ところで、LINQですが上記のようなクエリ構文とは別にメソッド構文というものも有ります。
両者のコードを下記に載せてみます。(文字数の関係でハイライトOFFです。)

//テスト用のデータ生成
List lst = new List();
lst.Add(new TestClass() { Name = "a", Id = 1 });
lst.Add(new TestClass() { Name = "b", Id = 2 });
lst.Add(new TestClass() { Name = "c", Id = 3 });
lst.Add(new TestClass() { Name = "d", Id = 5 });
lst.Add(new TestClass() { Name = "e", Id = 5 });
lst.Add(new TestClass() { Name = "f", Id = 4 });
lst.Add(new TestClass() { Name = "g", Id = 5 });

//検索条件の値。
int iFind=5;
string strFind = "a";

//LINQ クエリ構文での指定。Id が 5 またはNameが a のデータ
var query = from res in lst
where res.Id == iFind ||
res.Name.Equals("a")
select res;

//LINQ メソッド構文での指定。Id が 5 またはNameが a のデータ
var query2 = lst.Where(pram => pram.Id == iFind ||
pram.Name.Equals("a"))
.Select(pram => pram);


メソッド構文ではラムダ式を使っています。

ラムダ式もよくわかってませんが、C#2.0でデリゲートを簡単にかけるために匿名メソッドができました。その匿名メソッドをさらに簡潔に書けるようにしたもののようです。

=>演算子(goes to演算子)は「~に入力」と読むようですね。
左辺がデリゲートとして呼び出されるメソッドのパラメータが入るようです。(パラメータが複数場合は()でくくる必要がありますが、今回は一つなのでくくっていません)
右辺には式や文が入ります。ただLINQで使う場合は式が多いんじゃないかと思います。
ラムダ式の詳細は、@IT:C#ラムダ式 基礎文法最速マスタ@IT:第1回 ラムダ式 が分かりやすいです。

LINQのクエリ構文もメソッド構文もコンパイルすると全く同じコードになるようです。(@IT:第8回 LINQメソッド形式編が参考になります。MS的には、LINQ クエリ構文とメソッド構文 (C#)で「クエリ構文の方が単純で読みやすいため、クエリ構文を使用することをお勧めします。」とありました。)


ただ、オブジェクトLISTのWhereメソッドで検索する時、匿名メソッドだと無駄なコード吐き出すので、LINQのラムダかメソッド構文がいいということが、匿名メソッドとラムダ、そして LINQ の違い - vol 1,匿名メソッドとラムダ、そして LINQ の違い - vol 2で論じられてました。


言語の進歩に取り残されてる感が漂う3流PGでした。

追記:
動的に条件を設定する方法ですが、(.Net)LINQでラムダ式を動的に生成するに書いてみました。
by jehoshaphat | 2011-06-06 22:52 | .Net開発


<< (.Net)LINQでラムダ式... (.Net)WindowsAP... >>