SlideShare a Scribd company logo
1 of 39
Download to read offline
LINQソースでGO! 
IN 名古屋MS系秋祭り2013/09/21 
KOUJI MATSUI (@KEKYO2)
自己紹介 
けきょ。 
会社やってます。 
Micociとまどべんよっかいち。 
主にWindows。C#, C++/CLI, ATL, C++0x, x86/x64アセンブラ, WDM, Azure, TFS, OpenCV, Geo, JNI, 鯖管理, MCP少々, 自作PC, 昔マイコン, 複式簿記経理 
最近はWPFとPrismに足をツッコミ中。
LINQ知ってますか? 
ビデオチャット製品ではありませんw 
アイドルグループではありませんww 
.NET Framework 3.5 (C# 3.0)にて導入された、「統合言語クエリ」拡 張です。(Language Integrated Query) 
varresults = 
fromperson inpersons 
where(person.Age>= 30) && (person.IsFemale== true) 
orderbyperson.FirstName, person.LastName 
selectperson; 
foreach(varresult inresults) { 
Console.WriteLine(“{0} {1}”, result.FirstName, result.LastName); 
} 
人員一覧の中から、年齢が30歳以上、かつ女性の 人員を抽出し、名前・苗字の順でソートする 
クエリ結果はforeachで列挙可能
LINQはどんな場面で使える? 
配列にクエリを掛ける 
varpersons = new[] 
{ 
newPerson { FirstName=“Kouji”, LastName=“Matsui”, Age=41, IsFemale=false }, 
newPerson { FirstName=“Mogeko”, LastName=“Moge”, Age=35, IsFemale=true }, 
newPerson { FirstName=“Uhyo”, LastName=“Hidebu”, Age=31, IsFemale=true }, 
}; 
varresults = 
fromperson inpersons 
where(person.Age>= 30) && (person.IsFemale== true) 
orderbyperson.FirstName, person.LastName 
selectperson; 
Personクラスの配列 
配列から抽出する
LINQはどんな場面で使える? 
リストにクエリを掛ける 
varpersons = newList<Person>(); 
persons.Add( 
newPerson { FirstName=“Kouji”, LastName=“Matsui”, Age=41, IsFemale=false }); 
persons.Add( 
newPerson { FirstName=“Mogeko”, LastName=“Moge”, Age=35, IsFemale=true }); 
persons.Add( 
newPerson { FirstName=“Uhyo”, LastName=“Hidebu”, Age=31, IsFemale=true }); 
varresults = 
fromperson inpersons 
where(person.Age>= 30) && (person.IsFemale== true) 
orderbyperson.FirstName, person.LastName 
selectperson; 
抽出クエリ文は、配列の時と全く同じ 
リストにPersonを格納
LINQはどんな場面で使える? 
ジェネリックではないリストは駄目 
varpersons = newArrayList(); 
persons.Add( 
newPerson { FirstName=“Kouji”, LastName=“Matsui”, Age=41, IsFemale=false }); 
persons.Add( 
newPerson { FirstName=“Mogeko”, LastName=“Moge”, Age=35, IsFemale=true }); 
persons.Add( 
newPerson { FirstName=“Uhyo”, LastName=“Hidebu”, Age=31, IsFemale=true }); 
// 構文エラー 
varresult = 
fromperson inpersons 
where(person.Age>= 30) && (person.IsFemale== true) 
orderbyperson.FirstName, person.LastName 
selectperson; 
error CS1934: ソース型'System.Collections.ArrayList' のクエリパターンの実装が見つかりませんでした。'Where' が見つ かりません。範囲変数'person' の型を明示的に指定してください。 
ArrayListにPersonを格納
「Where」って何よ? 
「‘Where’ が見つかりません」… 
そもそも、その先頭大文字の「Where」って何? 
実はLINQのクエリ構文は、メソッド構文に置き換えられてコンパイ ルされる。 
// クエリ構文 
varresults = 
fromperson inpersons 
where(person.Age>= 30) && (person.IsFemale== true) 
orderbyperson.FirstName, person.LastName 
selectperson; 
// メソッド構文(コンパイル時にはこのように解釈される) 
varresults = persons. 
Where(person => (person.Age>= 30) && (person.IsFemale== true)). 
OrderBy(person => person.FirstName). 
ThenBy(person => person.LastName). 
Select(person => person); 
error CS1934: ソース型'System.Collections.ArrayList' のクエリパターンの実装が見つかりませんでした。'Where' が見つ かりません。範囲変数'person' の型を明示的に指定してください。
「Where」って何よ? 
ArrayListクラスのドキュメントを確認。 
Whereメソッドが無い。仕方ないか。
「Where」って何よ? 
そりゃ失礼。では正常なList<T>クラスのドキュメントを確認。 
やっぱり無いんですけど( ゚Д゚)
「Where」は拡張メソッド 
拡張メソッドは、C#3.0にて導入された。 
staticクラス内のstaticメソッドの第一引数に「this」を修飾する事で 定義できる。 
// 拡張メソッドの例。クラス名は完全に任意 
public staticclass SampleExtensions 
{ 
// 文字列をintに変換する拡張メソッド 
public staticintToInt32(this string stringValue) 
{ 
return int.Parse(stringValue); 
} 
} 
public sealed class MainClass 
{ 
public static void Main() 
{ 
varstring123 = “123”; 
varint123 = string123.ToInt32();// 拡張メソッドの呼び出し 
} } 
string型に対して、「this」の修飾 
string型インスタンスメソッドの呼び 出しのように見える(書ける)
「Where」は拡張メソッド 
Whereメソッドは、System.Linq.Enumerableクラスに定義されてい る。 
// System.Linq.Enumerable 
public static class Enumerable 
{ 
// Where拡張メソッド(擬似コード) 
public static IEnumerable<T> Where<T>( 
this IEnumerable<T>enumerable, 
Func<T, bool> predict) 
{ 
foreach(varvalue inenumerable) 
{ 
if(predict(value) == true) 
{ 
yield returnvalue; 
} 
} 
} 
} 
IEnumerable<T>インターフェイス型に 対して「this」の修飾
それで? 
でも、配列やリストは、IEnumerable<T>型じゃないよ? 
.NETの配列は、IEnumerable<T>インターフェイスを自動的に実装して いる。 
// 配列は、IEnumerable<T>を実装している 
varpersons = new[] 
{ 
newPerson { FirstName=“Kouji”, LastName=“Matsui” } 
}; 
IEnumerable<Person>personsEnumerable= persons;// OK 
List<T>クラスは、IEnumerable<T>を実装している。 
// List<T>は、IEnumerable<T>を実装している 
varpersons = new List<Person>(); 
persons.Add( 
newPerson { FirstName=“Kouji”, LastName=“Matsui” }); 
IEnumerable<Person>personsEnumerable= persons;// OK
IEnumerable<T> 
T型の配列T[] 
それで? 
List<T> 
IEnumerable<T> Where<T>(this IEnumerable<T>enumerable, …) 
つまり、両方とも抽象基底インターフェイスとして、 IEnumerable<T>インターフェイスを実装している。 
だから、どちらでも同じ 
Where拡張メソッドが使 える!! 
System.Linq.Enumerableクラス
ArrayListは? 
なぜArrayListクラスは駄目なのか? 
ArrayListクラスが実装しているインターフェイスは、IEnumerable<T> ではなく、IEnumerableインターフェイス。 
IEnumerableインターフェイスのWhere拡張メソッドは存在しない。 
じゃあ、全く使えないかというと、要するにT型を特定して、ジェネリッ クなIEnumerable<T>に変換すればいい。 
// ArraListを用意 
varpersons = newArrayList(); 
// (ArrayListに様々なインスタンスを追加) 
// すべての要素をキャスト(キャストに失敗すれば例外がスロー) 
IEnumerable<Person>persons2 = persons.Cast<Person>(); // OK 
// 又は、指定された型のインスタンスだけを抽出 
IEnumerable<Person>persons3 = persons.TypeOf<Person>(); // OK 
Cast・TypeOfメソッドは、 
「this IEnumerable」と定義された拡張メソッド。
ところで。 
クエリの結果をforeachで回してたっけ。 
varresults= 
fromperson inpersons 
where(person.Age>= 30) && (person.IsFemale== true) 
orderbyperson.FirstName, person.LastName 
selectperson; 
foreach(varresult inresults) { 
Console.WriteLine(“{0} {1}”, result.FirstName, result.LastName); 
} 
ぐるぐる 
foreachで回すことができる条件は?
今さらforeach 
foreachで回すことができるインスタンスは、IEnumerableインターフェイスを 実装していること。 
IEnumerableって言うと、配列とか、リストだっけ… 
// 配列 
varpersons= new[] 
{ 
newPerson { FirstName=“Kouji”, LastName=“Matsui”, Age=41, IsFemale=false }, 
newPerson { FirstName=“Mogeko”, LastName=“Moge”, Age=35, IsFemale=true }, 
newPerson { FirstName=“Uhyo”, LastName=“Hidebu”, Age=31, IsFemale=true }, 
}; 
// 配列を回してみた 
foreach(varperson inpersons) { 
Console.WriteLine(“{0} {1}”, person.FirstName, person.LastName); 
} 
なんだ、LINQクエリと一緒じゃん。 
一緒、なのか??( ゚Д゚) 
IEnumerable<T> 
T型の配列T[] 
List<T> 
IEnumerable 
継承・実装関係
配列・リスト・そしてLINQクエリ 
IEnumerable<T>もOKなので、LINQクエリはforeachでそのまま回せる。 
「逆に言えば」、LINQクエリはIEnumerable<T>インターフェイスを実装し ている? 
と言う事は? 
// 実はLINQクエリの結果はIEnumerable<T> 
IEnumerable<Person> results= 
fromperson inpersons 
where(person.Age>= 30) && (person.IsFemale== true) 
orderbyperson.FirstName, person.LastName 
selectperson; 
// 前段のLINQクエリに対して、更にLINQクエリを適用する 
IEnumerable<Person> results2 = 
fromresult inresults 
whereresult.LastName.StartsWith(“Suzuki”) == true 
selectresult; 
更にこの結果に対してLINQクエリを…
効率は? 
LINQクエリを数珠つなぎにして、効率悪くないの? 
悪いとも言えるし、変わらないともいえる。 
where絞り込み条件を完全に統合できるなら、その方が効率が良い。 
// where条件をまとめる 
varresults = 
fromperson inpersons 
where(person.Age>= 30) && (person.IsFemale== true) && 
(result.LastName.StartsWith(“Suzuki”) == true) 
orderbyperson.FirstName, person.LastName 
selectperson; 
クエリの意味が変わってしまわないように注意
起源を思い出せ 
効率が変わらないって? 
クエリ構文は、メソッド構文に置き換えられてコンパイルされる。 
// まとめると、単に連結されただけ。 
varresults2= persons. 
Where(person => (person.Age>= 30) && (person.IsFemale== true)). 
OrderBy(person => person.FirstName). 
ThenBy(person => person.LastName). 
Select(person => person). // ← しいて言えばここが無駄 
Where(result => result.LastName.StartsWith(“Suzuki”) == true). 
Select(result => result); 
varresults= persons. 
Where(person => (person.Age>= 30) && (person.IsFemale== true)). 
OrderBy(person => person.FirstName). 
ThenBy(person => person.LastName). 
Select(person => person); 
varresults2 = results. 
Where(result => result.LastName.StartsWith(“Suzuki”) == true). 
Select(result => result); 
クエリ構文だと、クエリが分割されているだけで 効率が悪いように見えるが、実際はそれほどでも ない。
結局のところ 
LINQクエリは、IEnumerable<T>インターフェイスを返すメソッドを数珠つ なぎにしただけ。 
// 全てが、IEnumerable<T>インターフェイスを利用した、拡張メソッド群の呼び 出しで解決される。 
varresults2 = persons. 
Where(person => (person.Age>= 30) && (person.IsFemale== true)). 
OrderBy(person => person.FirstName). 
ThenBy(person => person.LastName). 
Select(person => person). 
Where(result => result.LastName.StartsWith(“Suzuki”) == true). 
Select(result => result); 
// System.Linq.Enumerableクラス 
public static IEnumerable<T> Where<T>(thisIEnumerable<T> enumerable, …); 
public static IEnumerable<T> Select<T>(thisIEnumerable<T> enumerable, …); 
public static IEnumerable<T> OrderBy<T>(thisIEnumerable<T> enumerable, …); 
public static IEnumerable<T> ThenBy<T>(thisIEnumerable<T> enumerable, …); 
これらは全て、Enumerableクラスに定義さ れている拡張メソッド群 
OrderByとThenByは込み入った理由から 本当はこの通りではないが、同じように理解し てよい
一体、ソースの話はどこにww 
 前節までに、LINQクエリの肝は「IEnumerable<T>インターフェイス」と、そ 
の拡張メソッド群であることが明らかになりました。というか、これを強くイメージ 
してほしかったので、長々と解説しました。 
 言い換えると、「IEnumerable<T>インターフェイスのインスタンスを返しさ 
えすれば、フリーダムにやってOK」って事です。 
< マダー?
IEnumerable<T>を返す 
LINQで使える独自のメソッドを作りたい。例として、「指定された個数の乱数 を返す」LINQソースを考える。 
// イケてない実装(配列を作って、乱数を格納して返す) 
publicIEnumerable<int> GetRandomNumbers(intcount) 
{ 
varr = newRandom(); 
varresults = new int[count]; 
for(varindex = 0; index < results.Length; index++) { 
results[index] = r.Next(); 
} 
returnresults;// 配列はIEnumerable<T>を実装しているのでOK 
} 
// こう使える 
varresults = 
fromrninGetRandomNumbers(1000000) // これって… 
where(rn% 2) == 0 
selectrn; 
個数がデカいとちょっと…
オンザフライで乱数を生成(1) 
要するに、IEnumerable<T>で返せばいいのだから、配列やリストでなくても良 い。IEnumerable<T>を実装した、独自のクラスを定義する。 
IEnumerable<T>は、IEnumerator<T>のファクトリとなっているので、これ らを実装する。 
// IEnumerable<int>を実装したクラスを定義 
internal sealed class RandomNumberEnumerable: IEnumerable<int> 
{ 
private readonlyintcount_;// 個数を記憶する 
publicRandomNumberIEnumerable(intcount) 
{ 
count_ = count; 
} 
publicIEnumerator<int> GetEnumerator() 
{ 
// RandomNumberEnumeratorを作って返す(ファクトリメソッド) 
return new RandomNumberEnumerator(count_); 
} 
IEnumeratorIEnumerable.GetEnumerator() 
{ 
// 非ジェネリック実装は、単にジェネリック実装を呼び出す 
return this.GetEnumerator(); 
} 
}
オンザフライで乱数を生成(2) 
GetEnumerator()はIEnumerator<T>を返す必要があるので、そのた めのクラスを準備。 
// 乱数生成の本体クラス 
internal sealed class RandomNumberEnumerator: IEnumerator<int> 
{ 
private readonlyRandom r_ = newRandom(); 
private readonlyintcount_; 
private intremains_; 
publicRandomNumberEnumerator(intcount) 
{ 
count_ = count; 
remains_ = count; 
} 
public intCurrent 
{ 
get; 
private set; 
} 
// 次があるかどうかを返す 
publicboolMoveNext() 
{ 
if (remains_ >= 1) 
{ 
remains_--; 
this.Current= r.Next(); // 次の値を保持 
return true; 
} 
return false; 
} 
} 
実際には、Resetメソッドも必要…
オンザフライで乱数を生成(3) 
やっと完成。 
// オンザフライ出来た! 
publicIEnumerable<int> GetRandomNumbers(intcount) 
{ 
// RandomNumberEnumerableクラスを生成 
return new RandomNumberEnumerable(count); 
} 
// こう使える 
varresults = 
fromrninGetRandomNumbers(1000000) // メモリを過度に消費しない!! 
where(rn% 2) == 0 
selectrn; 
め、面倒クサ過ぎるorz
yield return 
C#2.0にて、「yield」予約語が導入された。 
これを使うと、IEnumerableインターフェイスの実装が劇的に簡単に! (つまり、前節の方法は、.NET 1.1までの方法) 
// イケてる実装 
publicIEnumerable<int> GetRandomNumbers(intcount) 
{ 
varr = newRandom(); 
for(varindex = 0; index < count; index++) { 
yield return r.Next();// yield returnって書くだけ!! 
} 
} 
// こう使える 
varresults = 
fromrninGetRandomNumbers(1000000) // 勿論、メモリ消費しない 
where(rn% 2) == 0 
selectrn; 
yieldを使うと、コンパイル時に、自動的に前述 のような内部クラスが生成される 
(ステートマシンの生成)
yieldを使って、拡張メソッド 
任意数のIEnumerable<T>インスタンスを結合する拡張メソッドを作る。 
// 適当なstaticクラスに定義 
publicstaticIEnumerable<T> Concats<T>( 
this IEnumerable<T> enumerable, 
paramsIEnumerable<T>[] rhss) 
{ 
// まず、自分を全て列挙 
foreach(varvalue inenumerable) 
{ 
yieldreturnvalue; 
} 
// 可変引数群を列挙 
foreach(varrhsinrhss) { 
// 個々の引数を列挙 foreach(varvalue inrhs) 
{ 
yieldreturnvalue; 
} 
} 
} 
可変引数群を受け取る
yieldを使って、拡張メソッド 
// 配列 
varpersons1 = new[] 
{ 
newPerson { FirstName=“Kouji”, LastName=“Matsui”, Age=41, IsFemale=false }, 
newPerson { FirstName=“Mogeko”, LastName=“Moge”, Age=35, IsFemale=true }, 
newPerson { FirstName=“Uhyo”, LastName=“Hidebu”, Age=31, IsFemale=true }, 
}; 
// リスト 
varpersons2 = newList<Person>(); 
persons2.Add(newPerson { FirstName=“Kouji”, LastName=“Matsui”, Age=41, IsFemale=false }); 
persons2.Add(newPerson { FirstName=“Mogeko”, LastName=“Moge”, Age=35, IsFemale=true }); 
persons2.Add(newPerson { FirstName=“Uhyo”, LastName=“Hidebu”, Age=31, IsFemale=true }); 
// 何らかのLINQクエリ 
varpersons3 = 
fromperson inpersonsX 
where(person.Age>= 30) && (person.IsFemale== true) 
selectperson; 
// 全部結合 
varresults = persons1.Concats(persons2, persons3); 
この部分が可変引数群(rhss)
yieldでこんな事も可能 
yieldによって勝手にステートマシンが作られるので、逆手にとって… 
// 移動角度群を返すLINQソース 
publicstaticIEnumerable<double> EnemyAngles() 
{ 
// 敵の移動角度を以下のシーケンスで返す 
yieldreturn0.0; 
yieldreturn32.0; 
yieldreturn248.0; 
yieldreturn125.0; 
yieldreturn66.0; 
yieldreturn321.0; 
// 10ステップはランダムな方角に移動 
varr = newRandom(); 
for(varindex = 0; index < 10; index++) 
{ 
yieldreturnr.Next(360); 
} 
// 最後に少し動いて死亡 
yieldreturn37.0; 
yieldreturn164.0; 
} 
foreachで回せば、これらの順で値が取得出来る。 
もちろん、LINQクエリで値を加工することも可能 
重要なのは、yieldを使う事で、返却する値を自由 自在にコントロールできると言う事 
単独で値を返したり、ループさせたり、それらを組み 合わせたりもOK
必ずIEnumerable<T>? 
LINQソースとなるためには、必ずIEnumerable<T>を返さなければならな いのか? 
// 例えば、パラレルLINQクエリ 
varresults = 
fromperson inpersons.AsParallel() 
where(person.Age>= 30) && (person.IsFemale== true) 
orderbyperson.FirstName, person.LastName 
selectperson; 
// メソッド構文 
varresults = persons. 
AsParallel(). 
Where(person => (person.Age>= 30) && (person.IsFemale== true)). 
OrderBy(person => person.FirstName). 
ThenBy(person => person.LastName). 
Select(person => person); 
AsParallelするだけで、あとは普通のLINQと 変わらないよ?
必ずIEnumerable<T>? 
パラレルLINQクエリの結果は、実はParallelQuery<T>型。 
// 似ているようで、違うのか? 
ParallelQuery<T>results = persons. 
AsParallel(). 
Where(person => (person.Age>= 30) && (person.IsFemale== true)). 
OrderBy(person => person.FirstName). 
ThenBy(person => person.LastName). 
Select(person => person);
必ずIEnumerable<T>? 
ParallelQuery<T>クラスは、IEnumerable<T>インターフェイスを実装 している。 
じゃあ、Where拡張メソッドの呼び出しは、結局同じってこと?? 
IEnumerable<T> 
ParallelQuery<T> 
IEnumerable<T> Where<T>(this IEnumerable<T>enumerable, …) 
System.Linq.Enumerableクラス
ParallelEnumerableクラス 
ParallelQuery<T>クラスに対応するWhere拡張メソッドは、 Enumerableクラスではなく、ParallelEnumerableクラスに定義されてい る。 
C#コンパイラは、型がより一致する拡張メソッドを自動的に選択するため、 ParallelQuery<T>に対してWhereを呼び出すと、 ParallelEnumerable.Whereが呼び出される。 
IEnumerable<T> Where<T>(this IEnumerable<T>enumerable, …) 
ParallelQuery<T> Where<T>(this ParallelQuery<T>enumerable, …) 
IEnumerable<T> 
ParallelQuery<T> 
System.Linq.Enumerableクラス 
System.Linq.ParallelEnumerableクラス 
ParallelQuery<T>の場合は、こっちのWhereが呼 び出される。この実装がパラレルLINQを実現する。
わざと似せている 
ParallelEnumerableクラスには、Enumerableクラスに定義されているメソッ ドと同じシグネチャ(但し、IEnumerable<T> → ParallelQuery<T>)の、 全く異なる実装が定義されている。 
// System.Linq.ParallelEnumerableクラス 
public static ParallelQuery<T> AsParallel<T>(thisIEnumerable<T> enumerable); 
public static ParallelQuery<T> Where<T>(thisParallelQuery<T> enumerable, …); 
public static ParallelQuery<T> Select<T>(thisParallelQuery<T> enumerable, …); 
public static ParallelQuery<T> OrderBy<T>(thisParallelQuery<T> enumerable, …); 
public static ParallelQuery<T> ThenBy<T>(thisParallelQuery<T> enumerable, …); 
戻り値の型も、ParallelQuery<T>となっているので、 
// メソッドの連結 
ParallelQuery<T> results = persons. 
AsParallel(). 
Where(person => (person.Age>= 30) && (person.IsFemale== true)). 
OrderBy(person => person.FirstName). 
ThenBy(person => person.LastName). 
Select(person => person; 
これらの戻り値の型は、すべからくParallelQuery<T>型。 
だから、全てParallelEnumerableの実装が使われる。 
→これによって、クエリのパラレル実行が行われる。
まだある、似て異なる実装 
LINQto SQLやLINQ to EntitiesのデータベースコンテキストからLINQク エリを記述すると、IEnumerable<T>ではなく、IQueryable<T>が返さ れる。 
// LINQ to Entitiesに対して、LINQクエリを記述する 
varresults = 
fromperson inpersonsContext// DBコンテキストがソース 
where(person.Age>= 30) && (person.IsFemale== true) 
orderbyperson.FirstName, person.LastName 
selectperson; 
// メソッド構文と戻り値の型 
IQueryable<Person> results = personsContext. 
Where(person => (person.Age>= 30) && (person.IsFemale== true)). 
OrderBy(person => person.FirstName). 
ThenBy(person => person.LastName). 
Select(person => person); 
IQueryable<T>
まだある、似て異なる実装 
IQueryable<T>に対応するWhere拡張メソッドは、Enumerableクラス ではなく、Queryableクラスに定義されている。 
考え方はパラレルLINQと同じ。 
IEnumerable<T> Where<T>(this IEnumerable<T>enumerable, …) 
IQueryable<T> Where<T>(this IQueryable<T>queryable, …) 
IEnumerable<T> 
IQueryable<T> 
System.Linq.Enumerableクラス 
System.Linq.Queryableクラス 
データベースにWHERE句を送信するた めの仕掛けを持った実装。
やっぱりLINQソースは 
IEnumerable<T>を継承したクラスやインターフェイスを使うのか? 
ReactiveExtensionライブラリが最後の常識を覆す。 
// マウス移動イベント発生時に座標をフィルタする 
IObservable<Point>rx= 
Observable.FromEvent<MouseEventArgs>(window, “MouseMove”). 
Select(ev=> ev.EventArgs.GetPosition(window)). 
Where(pos=> (pos.X< 100) && (pos.Y< 100)); 
// rxの条件が満たされたときに実行する内容を記述 
rx.Subscribe(pos=> 
{ 
window.Text= string.Format(“{0}, {1}”, pos.X, pos.Y); 
}); 
IObservable<T>は、IEnumerable<T>と全く関係がない。 
しかし、WhereやSelect拡張メソッドを用意する事で、まるで LINQクエリのように見えるようにしている。
まとめ 
ベーシックなLINQクエリは、すべからくIEnumerable<T>を使用す る。その場合、Enumerableクラスに定義された拡張メソッドを使用 して、LINQの機能を実現している。 
独自の拡張メソッドを定義すれば、LINQ演算子を追加できる。 
独自のLINQソースを作るなら、yield構文を使うと良い。 
拡張されたLINQクエリ(パラレルLINQやLINQ to Entitiesなど)は、 IEnumerable<T>を継承した、新たなクラスやインターフェイスを使 用して、拡張メソッドを切り替えさせる事で、似て異なる動作を実 現する。 これにより、既存の拡張メソッドの動作に影響を与えることなく、 かつ、容易に理解可能なAPIを生み出すことができる。 
IEnumerable<T>と全く関係のない型を使用したとしても、まるで LINQクエリのように見せることができる。 これを「Fluent API」パターンと呼ぶ。 Fluent APIを用意すれば、LINQクエリのようなフレンドリ感と、VS 上でのサクサクタイピングが実現する。
ご静聴ありがとうございましたm(_ _)m

More Related Content

What's hot

Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回演習の解説Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回演習の解説JPCERT Coordination Center
 
PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門kwatch
 
PerlとSQLのいろいろ
PerlとSQLのいろいろPerlとSQLのいろいろ
PerlとSQLのいろいろTakuya Tsuchida
 
Javaセキュアコーディングセミナー東京第3回演習の解説
Javaセキュアコーディングセミナー東京第3回演習の解説Javaセキュアコーディングセミナー東京第3回演習の解説
Javaセキュアコーディングセミナー東京第3回演習の解説JPCERT Coordination Center
 
Androidの通信周りのコーディングについて
Androidの通信周りのコーディングについてAndroidの通信周りのコーディングについて
Androidの通信周りのコーディングについてShoichi Takagi
 
Javaセキュアコーディングセミナー東京第3回講義
Javaセキュアコーディングセミナー東京第3回講義Javaセキュアコーディングセミナー東京第3回講義
Javaセキュアコーディングセミナー東京第3回講義JPCERT Coordination Center
 
Pythonで始めるDropboxAPI
Pythonで始めるDropboxAPIPythonで始めるDropboxAPI
Pythonで始めるDropboxAPIDaisuke Igarashi
 
traitを使って楽したい話
traitを使って楽したい話traitを使って楽したい話
traitを使って楽したい話infinite_loop
 
Javaプログラミング入門【第2回】
Javaプログラミング入門【第2回】Javaプログラミング入門【第2回】
Javaプログラミング入門【第2回】Yukiko Kato
 
C++0x 言語の未来を語る
C++0x 言語の未来を語るC++0x 言語の未来を語る
C++0x 言語の未来を語るAkira Takahashi
 
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和schoowebcampus
 
JavaのGenericsとは?
JavaのGenericsとは?JavaのGenericsとは?
JavaのGenericsとは?Kenji Nakamura
 
Java SE 7 InvokeDynamic in JRuby
Java SE 7 InvokeDynamic in JRubyJava SE 7 InvokeDynamic in JRuby
Java SE 7 InvokeDynamic in JRubyHiroshi Nakamura
 
わかるコードを書くために For writing clean code
わかるコードを書くために For writing clean codeわかるコードを書くために For writing clean code
わかるコードを書くために For writing clean codeEyes, JAPAN
 

What's hot (20)

Objc lambda
Objc lambdaObjc lambda
Objc lambda
 
Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回演習の解説Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回演習の解説
 
PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門
 
Project lambda
Project lambdaProject lambda
Project lambda
 
PerlとSQLのいろいろ
PerlとSQLのいろいろPerlとSQLのいろいろ
PerlとSQLのいろいろ
 
Javaセキュアコーディングセミナー東京第3回演習の解説
Javaセキュアコーディングセミナー東京第3回演習の解説Javaセキュアコーディングセミナー東京第3回演習の解説
Javaセキュアコーディングセミナー東京第3回演習の解説
 
講座Java入門
講座Java入門講座Java入門
講座Java入門
 
Androidの通信周りのコーディングについて
Androidの通信周りのコーディングについてAndroidの通信周りのコーディングについて
Androidの通信周りのコーディングについて
 
Javaセキュアコーディングセミナー東京第3回講義
Javaセキュアコーディングセミナー東京第3回講義Javaセキュアコーディングセミナー東京第3回講義
Javaセキュアコーディングセミナー東京第3回講義
 
Pythonで始めるDropboxAPI
Pythonで始めるDropboxAPIPythonで始めるDropboxAPI
Pythonで始めるDropboxAPI
 
traitを使って楽したい話
traitを使って楽したい話traitを使って楽したい話
traitを使って楽したい話
 
Javaプログラミング入門【第2回】
Javaプログラミング入門【第2回】Javaプログラミング入門【第2回】
Javaプログラミング入門【第2回】
 
C++0x 言語の未来を語る
C++0x 言語の未来を語るC++0x 言語の未来を語る
C++0x 言語の未来を語る
 
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
 
C#6.0の新機能紹介
C#6.0の新機能紹介C#6.0の新機能紹介
C#6.0の新機能紹介
 
JavaのGenericsとは?
JavaのGenericsとは?JavaのGenericsとは?
JavaのGenericsとは?
 
Clojure
ClojureClojure
Clojure
 
Java SE 7 InvokeDynamic in JRuby
Java SE 7 InvokeDynamic in JRubyJava SE 7 InvokeDynamic in JRuby
Java SE 7 InvokeDynamic in JRuby
 
わかるコードを書くために For writing clean code
わかるコードを書くために For writing clean codeわかるコードを書くために For writing clean code
わかるコードを書くために For writing clean code
 
Bluespec @waseda(PDF)
Bluespec @waseda(PDF)Bluespec @waseda(PDF)
Bluespec @waseda(PDF)
 

Similar to LINQソースでGO!

Ecmascript2015とその周辺について
Ecmascript2015とその周辺についてEcmascript2015とその周辺について
Ecmascript2015とその周辺について豊明 尾古
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 TipsTakaaki Suzuki
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)啓 小笠原
 
Infer.netによるldaの実装
Infer.netによるldaの実装Infer.netによるldaの実装
Infer.netによるldaの実装池田 直哉
 
メタな感じのプログラミング(プロ生 + わんくま 071118)
メタな感じのプログラミング(プロ生 + わんくま 071118)メタな感じのプログラミング(プロ生 + わんくま 071118)
メタな感じのプログラミング(プロ生 + わんくま 071118)Tatsuya Ishikawa
 
プログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコードプログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコードShigenori Sagawa
 
ぼくのかんがえたさいきょうのついったーくらいあんと
ぼくのかんがえたさいきょうのついったーくらいあんとぼくのかんがえたさいきょうのついったーくらいあんと
ぼくのかんがえたさいきょうのついったーくらいあんとYutaka Tsumori
 
よろしい、ならばMicro-ORMだ
よろしい、ならばMicro-ORMだよろしい、ならばMicro-ORMだ
よろしい、ならばMicro-ORMだNarami Kiyokura
 
AsyncTask アンチパターン
AsyncTask アンチパターンAsyncTask アンチパターン
AsyncTask アンチパターンHiroshi Kurokawa
 
T sql の parse と generator
T sql の parse と generatorT sql の parse と generator
T sql の parse と generatorOda Shinsuke
 
Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本Kota Mizushima
 
Scalaの限定継続の応用と基本(改訂版)
Scalaの限定継続の応用と基本(改訂版)Scalaの限定継続の応用と基本(改訂版)
Scalaの限定継続の応用と基本(改訂版)Kota Mizushima
 
Implementation patterns
Implementation patternsImplementation patterns
Implementation patternsTatsuya Maki
 
Linq To Fun
Linq To FunLinq To Fun
Linq To Fundeflis
 
RESTful開発フロントエンド編(SPA・AltJS・フレームワーク)
RESTful開発フロントエンド編(SPA・AltJS・フレームワーク)RESTful開発フロントエンド編(SPA・AltJS・フレームワーク)
RESTful開発フロントエンド編(SPA・AltJS・フレームワーク)K Tsukada
 
PCさえあればいい。
PCさえあればいい。PCさえあればいい。
PCさえあればいい。bleis tift
 
【macOSにも対応】AI入門「第3回:数学が苦手でも作って使えるKerasディープラーニング」
【macOSにも対応】AI入門「第3回:数学が苦手でも作って使えるKerasディープラーニング」【macOSにも対応】AI入門「第3回:数学が苦手でも作って使えるKerasディープラーニング」
【macOSにも対応】AI入門「第3回:数学が苦手でも作って使えるKerasディープラーニング」fukuoka.ex
 
APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。
APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。
APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。Satoshi Mimura
 

Similar to LINQソースでGO! (20)

Ecmascript2015とその周辺について
Ecmascript2015とその周辺についてEcmascript2015とその周辺について
Ecmascript2015とその周辺について
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)
 
Infer.netによるldaの実装
Infer.netによるldaの実装Infer.netによるldaの実装
Infer.netによるldaの実装
 
メタな感じのプログラミング(プロ生 + わんくま 071118)
メタな感じのプログラミング(プロ生 + わんくま 071118)メタな感じのプログラミング(プロ生 + わんくま 071118)
メタな感じのプログラミング(プロ生 + わんくま 071118)
 
プログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコードプログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコード
 
ぼくのかんがえたさいきょうのついったーくらいあんと
ぼくのかんがえたさいきょうのついったーくらいあんとぼくのかんがえたさいきょうのついったーくらいあんと
ぼくのかんがえたさいきょうのついったーくらいあんと
 
よろしい、ならばMicro-ORMだ
よろしい、ならばMicro-ORMだよろしい、ならばMicro-ORMだ
よろしい、ならばMicro-ORMだ
 
AsyncTask アンチパターン
AsyncTask アンチパターンAsyncTask アンチパターン
AsyncTask アンチパターン
 
Linqことはじめ
LinqことはじめLinqことはじめ
Linqことはじめ
 
T sql の parse と generator
T sql の parse と generatorT sql の parse と generator
T sql の parse と generator
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本
 
Scalaの限定継続の応用と基本(改訂版)
Scalaの限定継続の応用と基本(改訂版)Scalaの限定継続の応用と基本(改訂版)
Scalaの限定継続の応用と基本(改訂版)
 
Implementation patterns
Implementation patternsImplementation patterns
Implementation patterns
 
Linq To Fun
Linq To FunLinq To Fun
Linq To Fun
 
RESTful開発フロントエンド編(SPA・AltJS・フレームワーク)
RESTful開発フロントエンド編(SPA・AltJS・フレームワーク)RESTful開発フロントエンド編(SPA・AltJS・フレームワーク)
RESTful開発フロントエンド編(SPA・AltJS・フレームワーク)
 
PCさえあればいい。
PCさえあればいい。PCさえあればいい。
PCさえあればいい。
 
【macOSにも対応】AI入門「第3回:数学が苦手でも作って使えるKerasディープラーニング」
【macOSにも対応】AI入門「第3回:数学が苦手でも作って使えるKerasディープラーニング」【macOSにも対応】AI入門「第3回:数学が苦手でも作って使えるKerasディープラーニング」
【macOSにも対応】AI入門「第3回:数学が苦手でも作って使えるKerasディープラーニング」
 
APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。
APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。
APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。
 

More from Kouji Matsui

パターンでわかる! .NET Coreの非同期処理
パターンでわかる! .NET Coreの非同期処理パターンでわかる! .NET Coreの非同期処理
パターンでわかる! .NET Coreの非同期処理Kouji Matsui
 
Making archive IL2C #6-55 dotnet600 2018
Making archive IL2C #6-55 dotnet600 2018Making archive IL2C #6-55 dotnet600 2018
Making archive IL2C #6-55 dotnet600 2018Kouji Matsui
 
Matrix signal controller and BrainPad overview
Matrix signal controller and BrainPad overviewMatrix signal controller and BrainPad overview
Matrix signal controller and BrainPad overviewKouji Matsui
 
What's Functional?
What's Functional?What's Functional?
What's Functional?Kouji Matsui
 
Pitfall for WioLTE
Pitfall for WioLTEPitfall for WioLTE
Pitfall for WioLTEKouji Matsui
 
How to make the calculator
How to make the calculatorHow to make the calculator
How to make the calculatorKouji Matsui
 
Write common, run anywhere
Write common, run anywhereWrite common, run anywhere
Write common, run anywhereKouji Matsui
 
Locality of Reference
Locality of ReferenceLocality of Reference
Locality of ReferenceKouji Matsui
 
Nespのコード生成
Nespのコード生成Nespのコード生成
Nespのコード生成Kouji Matsui
 
C#でわかる こわくないMonad
C#でわかる こわくないMonadC#でわかる こわくないMonad
C#でわかる こわくないMonadKouji Matsui
 
You will be assimilated. Resistance is futile.
You will be assimilated. Resistance is futile.You will be assimilated. Resistance is futile.
You will be assimilated. Resistance is futile.Kouji Matsui
 
How to meets Async and Task
How to meets Async and TaskHow to meets Async and Task
How to meets Async and TaskKouji Matsui
 
Beachhead implements new opcode on CLR JIT
Beachhead implements new opcode on CLR JITBeachhead implements new opcode on CLR JIT
Beachhead implements new opcode on CLR JITKouji Matsui
 
Async deepdive before de:code
Async deepdive before de:codeAsync deepdive before de:code
Async deepdive before de:codeKouji Matsui
 
Thread affinity and CPS
Thread affinity and CPSThread affinity and CPS
Thread affinity and CPSKouji Matsui
 
Async DeepDive basics
Async DeepDive basicsAsync DeepDive basics
Async DeepDive basicsKouji Matsui
 
continuatioN Linking
continuatioN LinkingcontinuatioN Linking
continuatioN LinkingKouji Matsui
 
真Intermediate languageのキホン
真Intermediate languageのキホン真Intermediate languageのキホン
真Intermediate languageのキホンKouji Matsui
 
.NET Coreから概観する.NETのOSSへの取り組み
.NET Coreから概観する.NETのOSSへの取り組み.NET Coreから概観する.NETのOSSへの取り組み
.NET Coreから概観する.NETのOSSへの取り組みKouji Matsui
 

More from Kouji Matsui (20)

パターンでわかる! .NET Coreの非同期処理
パターンでわかる! .NET Coreの非同期処理パターンでわかる! .NET Coreの非同期処理
パターンでわかる! .NET Coreの非同期処理
 
Making archive IL2C #6-55 dotnet600 2018
Making archive IL2C #6-55 dotnet600 2018Making archive IL2C #6-55 dotnet600 2018
Making archive IL2C #6-55 dotnet600 2018
 
Matrix signal controller and BrainPad overview
Matrix signal controller and BrainPad overviewMatrix signal controller and BrainPad overview
Matrix signal controller and BrainPad overview
 
Fun with BrainPad
Fun with BrainPadFun with BrainPad
Fun with BrainPad
 
What's Functional?
What's Functional?What's Functional?
What's Functional?
 
Pitfall for WioLTE
Pitfall for WioLTEPitfall for WioLTE
Pitfall for WioLTE
 
How to make the calculator
How to make the calculatorHow to make the calculator
How to make the calculator
 
Write common, run anywhere
Write common, run anywhereWrite common, run anywhere
Write common, run anywhere
 
Locality of Reference
Locality of ReferenceLocality of Reference
Locality of Reference
 
Nespのコード生成
Nespのコード生成Nespのコード生成
Nespのコード生成
 
C#でわかる こわくないMonad
C#でわかる こわくないMonadC#でわかる こわくないMonad
C#でわかる こわくないMonad
 
You will be assimilated. Resistance is futile.
You will be assimilated. Resistance is futile.You will be assimilated. Resistance is futile.
You will be assimilated. Resistance is futile.
 
How to meets Async and Task
How to meets Async and TaskHow to meets Async and Task
How to meets Async and Task
 
Beachhead implements new opcode on CLR JIT
Beachhead implements new opcode on CLR JITBeachhead implements new opcode on CLR JIT
Beachhead implements new opcode on CLR JIT
 
Async deepdive before de:code
Async deepdive before de:codeAsync deepdive before de:code
Async deepdive before de:code
 
Thread affinity and CPS
Thread affinity and CPSThread affinity and CPS
Thread affinity and CPS
 
Async DeepDive basics
Async DeepDive basicsAsync DeepDive basics
Async DeepDive basics
 
continuatioN Linking
continuatioN LinkingcontinuatioN Linking
continuatioN Linking
 
真Intermediate languageのキホン
真Intermediate languageのキホン真Intermediate languageのキホン
真Intermediate languageのキホン
 
.NET Coreから概観する.NETのOSSへの取り組み
.NET Coreから概観する.NETのOSSへの取り組み.NET Coreから概観する.NETのOSSへの取り組み
.NET Coreから概観する.NETのOSSへの取り組み
 

LINQソースでGO!

  • 2. 自己紹介 けきょ。 会社やってます。 Micociとまどべんよっかいち。 主にWindows。C#, C++/CLI, ATL, C++0x, x86/x64アセンブラ, WDM, Azure, TFS, OpenCV, Geo, JNI, 鯖管理, MCP少々, 自作PC, 昔マイコン, 複式簿記経理 最近はWPFとPrismに足をツッコミ中。
  • 3. LINQ知ってますか? ビデオチャット製品ではありませんw アイドルグループではありませんww .NET Framework 3.5 (C# 3.0)にて導入された、「統合言語クエリ」拡 張です。(Language Integrated Query) varresults = fromperson inpersons where(person.Age>= 30) && (person.IsFemale== true) orderbyperson.FirstName, person.LastName selectperson; foreach(varresult inresults) { Console.WriteLine(“{0} {1}”, result.FirstName, result.LastName); } 人員一覧の中から、年齢が30歳以上、かつ女性の 人員を抽出し、名前・苗字の順でソートする クエリ結果はforeachで列挙可能
  • 4. LINQはどんな場面で使える? 配列にクエリを掛ける varpersons = new[] { newPerson { FirstName=“Kouji”, LastName=“Matsui”, Age=41, IsFemale=false }, newPerson { FirstName=“Mogeko”, LastName=“Moge”, Age=35, IsFemale=true }, newPerson { FirstName=“Uhyo”, LastName=“Hidebu”, Age=31, IsFemale=true }, }; varresults = fromperson inpersons where(person.Age>= 30) && (person.IsFemale== true) orderbyperson.FirstName, person.LastName selectperson; Personクラスの配列 配列から抽出する
  • 5. LINQはどんな場面で使える? リストにクエリを掛ける varpersons = newList<Person>(); persons.Add( newPerson { FirstName=“Kouji”, LastName=“Matsui”, Age=41, IsFemale=false }); persons.Add( newPerson { FirstName=“Mogeko”, LastName=“Moge”, Age=35, IsFemale=true }); persons.Add( newPerson { FirstName=“Uhyo”, LastName=“Hidebu”, Age=31, IsFemale=true }); varresults = fromperson inpersons where(person.Age>= 30) && (person.IsFemale== true) orderbyperson.FirstName, person.LastName selectperson; 抽出クエリ文は、配列の時と全く同じ リストにPersonを格納
  • 6. LINQはどんな場面で使える? ジェネリックではないリストは駄目 varpersons = newArrayList(); persons.Add( newPerson { FirstName=“Kouji”, LastName=“Matsui”, Age=41, IsFemale=false }); persons.Add( newPerson { FirstName=“Mogeko”, LastName=“Moge”, Age=35, IsFemale=true }); persons.Add( newPerson { FirstName=“Uhyo”, LastName=“Hidebu”, Age=31, IsFemale=true }); // 構文エラー varresult = fromperson inpersons where(person.Age>= 30) && (person.IsFemale== true) orderbyperson.FirstName, person.LastName selectperson; error CS1934: ソース型'System.Collections.ArrayList' のクエリパターンの実装が見つかりませんでした。'Where' が見つ かりません。範囲変数'person' の型を明示的に指定してください。 ArrayListにPersonを格納
  • 7. 「Where」って何よ? 「‘Where’ が見つかりません」… そもそも、その先頭大文字の「Where」って何? 実はLINQのクエリ構文は、メソッド構文に置き換えられてコンパイ ルされる。 // クエリ構文 varresults = fromperson inpersons where(person.Age>= 30) && (person.IsFemale== true) orderbyperson.FirstName, person.LastName selectperson; // メソッド構文(コンパイル時にはこのように解釈される) varresults = persons. Where(person => (person.Age>= 30) && (person.IsFemale== true)). OrderBy(person => person.FirstName). ThenBy(person => person.LastName). Select(person => person); error CS1934: ソース型'System.Collections.ArrayList' のクエリパターンの実装が見つかりませんでした。'Where' が見つ かりません。範囲変数'person' の型を明示的に指定してください。
  • 10. 「Where」は拡張メソッド 拡張メソッドは、C#3.0にて導入された。 staticクラス内のstaticメソッドの第一引数に「this」を修飾する事で 定義できる。 // 拡張メソッドの例。クラス名は完全に任意 public staticclass SampleExtensions { // 文字列をintに変換する拡張メソッド public staticintToInt32(this string stringValue) { return int.Parse(stringValue); } } public sealed class MainClass { public static void Main() { varstring123 = “123”; varint123 = string123.ToInt32();// 拡張メソッドの呼び出し } } string型に対して、「this」の修飾 string型インスタンスメソッドの呼び 出しのように見える(書ける)
  • 11. 「Where」は拡張メソッド Whereメソッドは、System.Linq.Enumerableクラスに定義されてい る。 // System.Linq.Enumerable public static class Enumerable { // Where拡張メソッド(擬似コード) public static IEnumerable<T> Where<T>( this IEnumerable<T>enumerable, Func<T, bool> predict) { foreach(varvalue inenumerable) { if(predict(value) == true) { yield returnvalue; } } } } IEnumerable<T>インターフェイス型に 対して「this」の修飾
  • 12. それで? でも、配列やリストは、IEnumerable<T>型じゃないよ? .NETの配列は、IEnumerable<T>インターフェイスを自動的に実装して いる。 // 配列は、IEnumerable<T>を実装している varpersons = new[] { newPerson { FirstName=“Kouji”, LastName=“Matsui” } }; IEnumerable<Person>personsEnumerable= persons;// OK List<T>クラスは、IEnumerable<T>を実装している。 // List<T>は、IEnumerable<T>を実装している varpersons = new List<Person>(); persons.Add( newPerson { FirstName=“Kouji”, LastName=“Matsui” }); IEnumerable<Person>personsEnumerable= persons;// OK
  • 13. IEnumerable<T> T型の配列T[] それで? List<T> IEnumerable<T> Where<T>(this IEnumerable<T>enumerable, …) つまり、両方とも抽象基底インターフェイスとして、 IEnumerable<T>インターフェイスを実装している。 だから、どちらでも同じ Where拡張メソッドが使 える!! System.Linq.Enumerableクラス
  • 14. ArrayListは? なぜArrayListクラスは駄目なのか? ArrayListクラスが実装しているインターフェイスは、IEnumerable<T> ではなく、IEnumerableインターフェイス。 IEnumerableインターフェイスのWhere拡張メソッドは存在しない。 じゃあ、全く使えないかというと、要するにT型を特定して、ジェネリッ クなIEnumerable<T>に変換すればいい。 // ArraListを用意 varpersons = newArrayList(); // (ArrayListに様々なインスタンスを追加) // すべての要素をキャスト(キャストに失敗すれば例外がスロー) IEnumerable<Person>persons2 = persons.Cast<Person>(); // OK // 又は、指定された型のインスタンスだけを抽出 IEnumerable<Person>persons3 = persons.TypeOf<Person>(); // OK Cast・TypeOfメソッドは、 「this IEnumerable」と定義された拡張メソッド。
  • 15. ところで。 クエリの結果をforeachで回してたっけ。 varresults= fromperson inpersons where(person.Age>= 30) && (person.IsFemale== true) orderbyperson.FirstName, person.LastName selectperson; foreach(varresult inresults) { Console.WriteLine(“{0} {1}”, result.FirstName, result.LastName); } ぐるぐる foreachで回すことができる条件は?
  • 16. 今さらforeach foreachで回すことができるインスタンスは、IEnumerableインターフェイスを 実装していること。 IEnumerableって言うと、配列とか、リストだっけ… // 配列 varpersons= new[] { newPerson { FirstName=“Kouji”, LastName=“Matsui”, Age=41, IsFemale=false }, newPerson { FirstName=“Mogeko”, LastName=“Moge”, Age=35, IsFemale=true }, newPerson { FirstName=“Uhyo”, LastName=“Hidebu”, Age=31, IsFemale=true }, }; // 配列を回してみた foreach(varperson inpersons) { Console.WriteLine(“{0} {1}”, person.FirstName, person.LastName); } なんだ、LINQクエリと一緒じゃん。 一緒、なのか??( ゚Д゚) IEnumerable<T> T型の配列T[] List<T> IEnumerable 継承・実装関係
  • 17. 配列・リスト・そしてLINQクエリ IEnumerable<T>もOKなので、LINQクエリはforeachでそのまま回せる。 「逆に言えば」、LINQクエリはIEnumerable<T>インターフェイスを実装し ている? と言う事は? // 実はLINQクエリの結果はIEnumerable<T> IEnumerable<Person> results= fromperson inpersons where(person.Age>= 30) && (person.IsFemale== true) orderbyperson.FirstName, person.LastName selectperson; // 前段のLINQクエリに対して、更にLINQクエリを適用する IEnumerable<Person> results2 = fromresult inresults whereresult.LastName.StartsWith(“Suzuki”) == true selectresult; 更にこの結果に対してLINQクエリを…
  • 18. 効率は? LINQクエリを数珠つなぎにして、効率悪くないの? 悪いとも言えるし、変わらないともいえる。 where絞り込み条件を完全に統合できるなら、その方が効率が良い。 // where条件をまとめる varresults = fromperson inpersons where(person.Age>= 30) && (person.IsFemale== true) && (result.LastName.StartsWith(“Suzuki”) == true) orderbyperson.FirstName, person.LastName selectperson; クエリの意味が変わってしまわないように注意
  • 19. 起源を思い出せ 効率が変わらないって? クエリ構文は、メソッド構文に置き換えられてコンパイルされる。 // まとめると、単に連結されただけ。 varresults2= persons. Where(person => (person.Age>= 30) && (person.IsFemale== true)). OrderBy(person => person.FirstName). ThenBy(person => person.LastName). Select(person => person). // ← しいて言えばここが無駄 Where(result => result.LastName.StartsWith(“Suzuki”) == true). Select(result => result); varresults= persons. Where(person => (person.Age>= 30) && (person.IsFemale== true)). OrderBy(person => person.FirstName). ThenBy(person => person.LastName). Select(person => person); varresults2 = results. Where(result => result.LastName.StartsWith(“Suzuki”) == true). Select(result => result); クエリ構文だと、クエリが分割されているだけで 効率が悪いように見えるが、実際はそれほどでも ない。
  • 20. 結局のところ LINQクエリは、IEnumerable<T>インターフェイスを返すメソッドを数珠つ なぎにしただけ。 // 全てが、IEnumerable<T>インターフェイスを利用した、拡張メソッド群の呼び 出しで解決される。 varresults2 = persons. Where(person => (person.Age>= 30) && (person.IsFemale== true)). OrderBy(person => person.FirstName). ThenBy(person => person.LastName). Select(person => person). Where(result => result.LastName.StartsWith(“Suzuki”) == true). Select(result => result); // System.Linq.Enumerableクラス public static IEnumerable<T> Where<T>(thisIEnumerable<T> enumerable, …); public static IEnumerable<T> Select<T>(thisIEnumerable<T> enumerable, …); public static IEnumerable<T> OrderBy<T>(thisIEnumerable<T> enumerable, …); public static IEnumerable<T> ThenBy<T>(thisIEnumerable<T> enumerable, …); これらは全て、Enumerableクラスに定義さ れている拡張メソッド群 OrderByとThenByは込み入った理由から 本当はこの通りではないが、同じように理解し てよい
  • 21. 一体、ソースの話はどこにww  前節までに、LINQクエリの肝は「IEnumerable<T>インターフェイス」と、そ の拡張メソッド群であることが明らかになりました。というか、これを強くイメージ してほしかったので、長々と解説しました。  言い換えると、「IEnumerable<T>インターフェイスのインスタンスを返しさ えすれば、フリーダムにやってOK」って事です。 < マダー?
  • 22. IEnumerable<T>を返す LINQで使える独自のメソッドを作りたい。例として、「指定された個数の乱数 を返す」LINQソースを考える。 // イケてない実装(配列を作って、乱数を格納して返す) publicIEnumerable<int> GetRandomNumbers(intcount) { varr = newRandom(); varresults = new int[count]; for(varindex = 0; index < results.Length; index++) { results[index] = r.Next(); } returnresults;// 配列はIEnumerable<T>を実装しているのでOK } // こう使える varresults = fromrninGetRandomNumbers(1000000) // これって… where(rn% 2) == 0 selectrn; 個数がデカいとちょっと…
  • 23. オンザフライで乱数を生成(1) 要するに、IEnumerable<T>で返せばいいのだから、配列やリストでなくても良 い。IEnumerable<T>を実装した、独自のクラスを定義する。 IEnumerable<T>は、IEnumerator<T>のファクトリとなっているので、これ らを実装する。 // IEnumerable<int>を実装したクラスを定義 internal sealed class RandomNumberEnumerable: IEnumerable<int> { private readonlyintcount_;// 個数を記憶する publicRandomNumberIEnumerable(intcount) { count_ = count; } publicIEnumerator<int> GetEnumerator() { // RandomNumberEnumeratorを作って返す(ファクトリメソッド) return new RandomNumberEnumerator(count_); } IEnumeratorIEnumerable.GetEnumerator() { // 非ジェネリック実装は、単にジェネリック実装を呼び出す return this.GetEnumerator(); } }
  • 24. オンザフライで乱数を生成(2) GetEnumerator()はIEnumerator<T>を返す必要があるので、そのた めのクラスを準備。 // 乱数生成の本体クラス internal sealed class RandomNumberEnumerator: IEnumerator<int> { private readonlyRandom r_ = newRandom(); private readonlyintcount_; private intremains_; publicRandomNumberEnumerator(intcount) { count_ = count; remains_ = count; } public intCurrent { get; private set; } // 次があるかどうかを返す publicboolMoveNext() { if (remains_ >= 1) { remains_--; this.Current= r.Next(); // 次の値を保持 return true; } return false; } } 実際には、Resetメソッドも必要…
  • 25. オンザフライで乱数を生成(3) やっと完成。 // オンザフライ出来た! publicIEnumerable<int> GetRandomNumbers(intcount) { // RandomNumberEnumerableクラスを生成 return new RandomNumberEnumerable(count); } // こう使える varresults = fromrninGetRandomNumbers(1000000) // メモリを過度に消費しない!! where(rn% 2) == 0 selectrn; め、面倒クサ過ぎるorz
  • 26. yield return C#2.0にて、「yield」予約語が導入された。 これを使うと、IEnumerableインターフェイスの実装が劇的に簡単に! (つまり、前節の方法は、.NET 1.1までの方法) // イケてる実装 publicIEnumerable<int> GetRandomNumbers(intcount) { varr = newRandom(); for(varindex = 0; index < count; index++) { yield return r.Next();// yield returnって書くだけ!! } } // こう使える varresults = fromrninGetRandomNumbers(1000000) // 勿論、メモリ消費しない where(rn% 2) == 0 selectrn; yieldを使うと、コンパイル時に、自動的に前述 のような内部クラスが生成される (ステートマシンの生成)
  • 27. yieldを使って、拡張メソッド 任意数のIEnumerable<T>インスタンスを結合する拡張メソッドを作る。 // 適当なstaticクラスに定義 publicstaticIEnumerable<T> Concats<T>( this IEnumerable<T> enumerable, paramsIEnumerable<T>[] rhss) { // まず、自分を全て列挙 foreach(varvalue inenumerable) { yieldreturnvalue; } // 可変引数群を列挙 foreach(varrhsinrhss) { // 個々の引数を列挙 foreach(varvalue inrhs) { yieldreturnvalue; } } } 可変引数群を受け取る
  • 28. yieldを使って、拡張メソッド // 配列 varpersons1 = new[] { newPerson { FirstName=“Kouji”, LastName=“Matsui”, Age=41, IsFemale=false }, newPerson { FirstName=“Mogeko”, LastName=“Moge”, Age=35, IsFemale=true }, newPerson { FirstName=“Uhyo”, LastName=“Hidebu”, Age=31, IsFemale=true }, }; // リスト varpersons2 = newList<Person>(); persons2.Add(newPerson { FirstName=“Kouji”, LastName=“Matsui”, Age=41, IsFemale=false }); persons2.Add(newPerson { FirstName=“Mogeko”, LastName=“Moge”, Age=35, IsFemale=true }); persons2.Add(newPerson { FirstName=“Uhyo”, LastName=“Hidebu”, Age=31, IsFemale=true }); // 何らかのLINQクエリ varpersons3 = fromperson inpersonsX where(person.Age>= 30) && (person.IsFemale== true) selectperson; // 全部結合 varresults = persons1.Concats(persons2, persons3); この部分が可変引数群(rhss)
  • 29. yieldでこんな事も可能 yieldによって勝手にステートマシンが作られるので、逆手にとって… // 移動角度群を返すLINQソース publicstaticIEnumerable<double> EnemyAngles() { // 敵の移動角度を以下のシーケンスで返す yieldreturn0.0; yieldreturn32.0; yieldreturn248.0; yieldreturn125.0; yieldreturn66.0; yieldreturn321.0; // 10ステップはランダムな方角に移動 varr = newRandom(); for(varindex = 0; index < 10; index++) { yieldreturnr.Next(360); } // 最後に少し動いて死亡 yieldreturn37.0; yieldreturn164.0; } foreachで回せば、これらの順で値が取得出来る。 もちろん、LINQクエリで値を加工することも可能 重要なのは、yieldを使う事で、返却する値を自由 自在にコントロールできると言う事 単独で値を返したり、ループさせたり、それらを組み 合わせたりもOK
  • 30. 必ずIEnumerable<T>? LINQソースとなるためには、必ずIEnumerable<T>を返さなければならな いのか? // 例えば、パラレルLINQクエリ varresults = fromperson inpersons.AsParallel() where(person.Age>= 30) && (person.IsFemale== true) orderbyperson.FirstName, person.LastName selectperson; // メソッド構文 varresults = persons. AsParallel(). Where(person => (person.Age>= 30) && (person.IsFemale== true)). OrderBy(person => person.FirstName). ThenBy(person => person.LastName). Select(person => person); AsParallelするだけで、あとは普通のLINQと 変わらないよ?
  • 31. 必ずIEnumerable<T>? パラレルLINQクエリの結果は、実はParallelQuery<T>型。 // 似ているようで、違うのか? ParallelQuery<T>results = persons. AsParallel(). Where(person => (person.Age>= 30) && (person.IsFemale== true)). OrderBy(person => person.FirstName). ThenBy(person => person.LastName). Select(person => person);
  • 32. 必ずIEnumerable<T>? ParallelQuery<T>クラスは、IEnumerable<T>インターフェイスを実装 している。 じゃあ、Where拡張メソッドの呼び出しは、結局同じってこと?? IEnumerable<T> ParallelQuery<T> IEnumerable<T> Where<T>(this IEnumerable<T>enumerable, …) System.Linq.Enumerableクラス
  • 33. ParallelEnumerableクラス ParallelQuery<T>クラスに対応するWhere拡張メソッドは、 Enumerableクラスではなく、ParallelEnumerableクラスに定義されてい る。 C#コンパイラは、型がより一致する拡張メソッドを自動的に選択するため、 ParallelQuery<T>に対してWhereを呼び出すと、 ParallelEnumerable.Whereが呼び出される。 IEnumerable<T> Where<T>(this IEnumerable<T>enumerable, …) ParallelQuery<T> Where<T>(this ParallelQuery<T>enumerable, …) IEnumerable<T> ParallelQuery<T> System.Linq.Enumerableクラス System.Linq.ParallelEnumerableクラス ParallelQuery<T>の場合は、こっちのWhereが呼 び出される。この実装がパラレルLINQを実現する。
  • 34. わざと似せている ParallelEnumerableクラスには、Enumerableクラスに定義されているメソッ ドと同じシグネチャ(但し、IEnumerable<T> → ParallelQuery<T>)の、 全く異なる実装が定義されている。 // System.Linq.ParallelEnumerableクラス public static ParallelQuery<T> AsParallel<T>(thisIEnumerable<T> enumerable); public static ParallelQuery<T> Where<T>(thisParallelQuery<T> enumerable, …); public static ParallelQuery<T> Select<T>(thisParallelQuery<T> enumerable, …); public static ParallelQuery<T> OrderBy<T>(thisParallelQuery<T> enumerable, …); public static ParallelQuery<T> ThenBy<T>(thisParallelQuery<T> enumerable, …); 戻り値の型も、ParallelQuery<T>となっているので、 // メソッドの連結 ParallelQuery<T> results = persons. AsParallel(). Where(person => (person.Age>= 30) && (person.IsFemale== true)). OrderBy(person => person.FirstName). ThenBy(person => person.LastName). Select(person => person; これらの戻り値の型は、すべからくParallelQuery<T>型。 だから、全てParallelEnumerableの実装が使われる。 →これによって、クエリのパラレル実行が行われる。
  • 35. まだある、似て異なる実装 LINQto SQLやLINQ to EntitiesのデータベースコンテキストからLINQク エリを記述すると、IEnumerable<T>ではなく、IQueryable<T>が返さ れる。 // LINQ to Entitiesに対して、LINQクエリを記述する varresults = fromperson inpersonsContext// DBコンテキストがソース where(person.Age>= 30) && (person.IsFemale== true) orderbyperson.FirstName, person.LastName selectperson; // メソッド構文と戻り値の型 IQueryable<Person> results = personsContext. Where(person => (person.Age>= 30) && (person.IsFemale== true)). OrderBy(person => person.FirstName). ThenBy(person => person.LastName). Select(person => person); IQueryable<T>
  • 36. まだある、似て異なる実装 IQueryable<T>に対応するWhere拡張メソッドは、Enumerableクラス ではなく、Queryableクラスに定義されている。 考え方はパラレルLINQと同じ。 IEnumerable<T> Where<T>(this IEnumerable<T>enumerable, …) IQueryable<T> Where<T>(this IQueryable<T>queryable, …) IEnumerable<T> IQueryable<T> System.Linq.Enumerableクラス System.Linq.Queryableクラス データベースにWHERE句を送信するた めの仕掛けを持った実装。
  • 37. やっぱりLINQソースは IEnumerable<T>を継承したクラスやインターフェイスを使うのか? ReactiveExtensionライブラリが最後の常識を覆す。 // マウス移動イベント発生時に座標をフィルタする IObservable<Point>rx= Observable.FromEvent<MouseEventArgs>(window, “MouseMove”). Select(ev=> ev.EventArgs.GetPosition(window)). Where(pos=> (pos.X< 100) && (pos.Y< 100)); // rxの条件が満たされたときに実行する内容を記述 rx.Subscribe(pos=> { window.Text= string.Format(“{0}, {1}”, pos.X, pos.Y); }); IObservable<T>は、IEnumerable<T>と全く関係がない。 しかし、WhereやSelect拡張メソッドを用意する事で、まるで LINQクエリのように見えるようにしている。
  • 38. まとめ ベーシックなLINQクエリは、すべからくIEnumerable<T>を使用す る。その場合、Enumerableクラスに定義された拡張メソッドを使用 して、LINQの機能を実現している。 独自の拡張メソッドを定義すれば、LINQ演算子を追加できる。 独自のLINQソースを作るなら、yield構文を使うと良い。 拡張されたLINQクエリ(パラレルLINQやLINQ to Entitiesなど)は、 IEnumerable<T>を継承した、新たなクラスやインターフェイスを使 用して、拡張メソッドを切り替えさせる事で、似て異なる動作を実 現する。 これにより、既存の拡張メソッドの動作に影響を与えることなく、 かつ、容易に理解可能なAPIを生み出すことができる。 IEnumerable<T>と全く関係のない型を使用したとしても、まるで LINQクエリのように見せることができる。 これを「Fluent API」パターンと呼ぶ。 Fluent APIを用意すれば、LINQクエリのようなフレンドリ感と、VS 上でのサクサクタイピングが実現する。