Reactive Extensionsを学習するためのリソースまとめ
- 2011-01-26
1年半ほどDevLabsプロジェクトとして動いていたReactive Extensionsですが、ついにDevLabsを卒業し、Data Developer Center入りを果たしました。まずは、おめでとう!そして、これで安心してプロダクトに突っ込む事ができます。どれだけ有望そうに見えても、DevLabsのままではいつ消滅するか分からない。そういう先例(STM.NETがね、この死骸ページの虚しさ)もあった。また、Rxチームの前身はMicrosoft Live LabsでのVoltaというプロジェクトなわけですが、これは打ち切りでした!その魂はRxの可愛い鰻のアイコンで引き継がれ(Voltaからの継続使用)、ついに復活を遂げたという感動ストーリーがあるかないかは、特にない。それはともかくとして、私はこのアイコン好きです。
なお、Data Developer Centerはen-usとja-jpの格差が激しいので、日本語情報が充実するかは不透明というか多分しないというか、せめてja-jpからだと辿れないテクノロジが幾つかあるのだけは何とかして欲しい、RxもそうだしStreamInsightなんかも……。
学習リソースまとめ
Data Developer Centerのページが何だかごちゃごちゃしているので、少し情報を整理します。
ここのTutorials & ArticlesにあるCuring the asynchronous blues with the Reactive Extensions。これがハンズオンラボになっていて、基礎からチュートリアル式に触りながら学べるようになっています。まずは、これをこなすとRxではどのようにプログラミングするのか、どのような問題を解決できるのか、というのが見えるはずです。for .NETとfor JavaScriptがありますが、内容は同じです。両方を見ることで、Rxという、Linqという層を設けることで言語を超えた統一的な思考・統一的な記述が可能になっているという世界を垣間見ることができます。
続いて同ページの左下、Documentation HighlightsにあるDesign Guidelines。このドキュメントは非常に重要で、Rxにおける原理原則注意点実装の詳細が書かれているので、最初から読む必要はないのですが、ある程度Rxに慣れ親しんだら絶対に読むべき代物です。日本マイクロソフトは是非これを和訳してください!
RxチームのBart De Smetによるプレゼンテーション。Rxチームもあちこちでプレゼンやっていて、色々なビデオが残っているのですが、これが一番お薦め。導入から深いところまで過不足なく説明されていて大変分かりやすいし、グッとくるかと思われます。また、Channel 9のRxタグには動画がいっぱいあります。新機能を足すたびに動画で説明していたので英語圏のほうでは分かりやすいのだろうけれど、それ以外にとってはむしろ分かりづらいんだよこんちくしょう!を繰り広げてましたので良く分からない機能があったらとりあえず動画見に行くといいのではないかと思われます。
これは、お薦めしません。ほんと最初期に立てられたWikiで、皆が試行錯誤な段階で例が書かれた感じで、どうもわかってない感漂う今一つな例ばかり。いや、そりゃ初期なのでしょうがないのですが、如何せんそれから以後誰も追加も更新もしない寂れた廃墟なので、これ見て学ぼうとするのは少しシンドイ。(私も含めて)お前ら編集しろよって感じなのですが、どうしてこうなった……。
Rxについての情報交換は公式フォーラムで行われています。Rxチームの人も出てきますし、常連みたいな人が何人か張り付いてコードぺたぺた貼ってくれているので、サンプル集的な意味でもお薦め(前述のWikiよりも遥かに!)。何か使い方の分からないメソッドがあれば、検索に入れてみれば、きっと解説とコードが出てくるでしょう。
Windows Phone 7にはRxが標準搭載されていますので、当然MSDNにもリファレンスがあります。WP7の開発環境が日本語化してくれれば、念願のRxでの日本語IntelliSenseが!なのですが、まだなのですよね、残念。ちなみに、このWP7版は少し前のものがベースになっているので、必ずしも現在の最新版と一致するとは限りません。WP7版が出てから追加されたものは入っていないし、中には削られたものも……。なお、リファレンス自体はインストールディレクトリ Progam Files\Microsoft Cloud Programmability\Reactive Extensions にchmで転がってます。
あまりお薦めしません(笑) 初期は「メソッド探訪XX回」というフォーマットでやろうとしていましたが今はそれは放棄して完全に好き放題書いてます。壊滅的に整理されておらず、非常に分かりづらい。日本語でのちょっと突っ込んだ情報はここしかないというのは悲しいことです。一応、幾つか並べてみれば
Reactive Extensions入門 + メソッド早見解説表
linq.js & Reactive Extensions for JavaScript(RxJS)入門
RxとAsync CTPでの非同期のキャンセル・プログレス処理
Reactive Extensionsとエラーハンドリング
Rxを使って非同期プログラミングを簡単に
Reactive Extensionsの非同期周りの解説と自前実装
メソッド探訪第7回:IEnumerable vs IObservable
Rx(Reactive Extensions)を自前簡易再実装する
といったところでしょうか(全然絞れてないですね、あうあう)。ちょっと非同期にお熱だったので、非同期系に偏りがちな、特に近頃は。重要な○○の解説を出してないので早く書きたい!と思っている事項が、まだかなり沢山残っているので、今年も積極的に更新を続けたいと思っています。あとは私の Twitter:@neuecc で小さいコード書いて貼りつけたり、Rx関連な話題が目についたら反応したりはしてます。たまに。答えられることは答えられますが答えられないことは勿論答えられないので、私がダンマリとしてたら、こいつ分かってねーな、ということで、ぐぬぬぬ。もしくは風呂で寝てます。
その他のリソース
Reactive programmingというパラダイムで見ることが出来るので、他の言語での動きから分かることというのも、いっぱいあります。
F#から。この論文の著者のTomas Petricekは非常に有名な方で、そもそもSupervisor: Don Syme, Microsoft Research Cambridgeですしね。146ページとボリューム十分。ですが、私は「読んでません」よ。俺、F#を学んだらこの論文読むんだ……。とか思ってはやンヶ月。ようやく重い腰が上がってF#はぢめました。やってみるとF#は非常に面白く、更に教養として身につけておく、的なわけじゃなく今すぐ普通に実用的なので、実践 F#読んで一緒に学びましょうー。F#お薦め。
F#はファーストクラスイベントとして、デフォルトでフィルタリング程度なら可能になっているしで、むしろネイティブ対応だぜ的な勢いもありますね。少し触った感じだとmapとfilterぐらいなので、あくまで軽く、程度ではあるようですが。あと非同期ワークフローが実に興味深く有益な機能。
非同期ワークフローといったら、こちらも。C# 5.0に入るかも、なAsync機能のCTP。残念ながら英語版VSにしか入らないので簡単に触れはしないのですが……。Rx自体にもこのAsync CTP対応(GetAwaiterの実装)や、System.Linq.AsyncとしてAsyncEnumerableの実装などをしていて、Async CTPとは、切っても切れない密接さを見せているのですが、機能的にやはり被りつつあるので、どう上手く切り分けるのか、というのが難しいところです。Async CTPはもう少し突っつきたいのですが中々時間取れずな今現在。
ScalaでのReactiveの実装になるようです。Wiki -> Design Guidelines in Japanese は実にためになります。作者はC++でのLinq(酷い形容ですがC#erの戯言なので許して!) であるOvenのかた。Enumerable-Observableみたいなことを感じつつそこはしかしC++もScalaも分からないのでもごもご。
概要編のほかEvent編、Behavior編が。Haskellはよくわからなくても雰囲気は分かる(ぉ
こうして俯瞰してみても、Rxは実用に踏み出しているという点で、一歩抜けてるのではないかと思います。
Rxの入手方法・パッケージ・DLL内容について
対応プラットフォームはいっぱいありますが、Get Reactive Extensions for .NETからRx for All Platformsを選択すれば全部インストールされますんで、それでいいと思われます。又はNuGetに対応しているので、それを使うのも良いでしょう。
画像はNuGetに登録されているRxのもの。多すぎである。NuGetでも多すぎて困るのですが、普通にインストールした場合は、やたら小分けされた大量のDLLをインストールしてくるので、何をどう選べばいいのかさっぱり分かりません。というわけで、それの解説を少し。
System.CoreEx // Scheduler,Disposableなどの必須クラス群
System.Observable // Silverlightのみ
NuGetだとRx-Core。System.ObservableはIObserver/IObservableのインターフェイス定義で、.NET4なら標準入りしているので不要ですがSilverlightでは、こちらの参照も必要になります。
System.Reactive // Observable拡張メソッド
NuGetだとRx-Main。Observableの拡張メソッド群が入っているので、CoreExとReactiveがRxを使う際に必須となる参照と考えるといいです。
System.Reactive.ClientProfile // Stream周りをRxで非同期Readする補助拡張メソッド群
System.Reactive.ExtendedProfile // IHttpHandler使ってモニョモニョなサーバー利用での補助拡張メソッド群
System.Reactive.Testing // テストでのモックを作ったりする時に使いたいクラス群
この3つはオプション。ClientProfileはstreamにAsyncRead/AsyncReadLineというのが入っていて、そのまんまな挙動です。ちなみにAsyncReadLineはbyteをそのまんま切り出しているだけ(つまり日本語で使うとぶっ壊れる)のでまるっきり実用になってません。ふざけんな。というわけで使わないの推奨。
ただ、標準のRxだけだと、この辺のReadは自前で書かなければならなくて少々面倒くさいので、こういったあると便利系のものはあったほうがいい。恐らく、今後拡充されてここに追加されていくのではないかと思われます。私もReactive Extensions用のWebRequest拡張メソッドとか書いちゃってますが、標準でそういうの入ってくれれば手間なくて素敵。ExtendedProfileはよくわからないけどClientProfileと同じく作りは適当な気がする。Testingはあとで調べると思って放置中。でも概念は多分有益だと思うので、そのうちしっかり調べておきたい。
System.Interactive // Enumerable拡張メソッド(EnumerableEx)
こちらはRxとは独立していて、IEnumerableへの拡張メソッド群になっています。気の利いたのが色々入っていて便利。linq.jsにもここからパクッた、じゃなくて名前を統一させて入れたのが幾つかあります。あと、みんなが待望していたForEachがRunという名前で入っていますよ!それだけでもはや必須コンポーネントですね!
なお、突然Ixという表記を見たら、こちらのこと(もしくはIEnumerable全体)を指します。Interactive Extensions。用語としては、Pull-Enumerable-Interactive-IxとPush-Observable-Reactive-Rx となっています。紛らわしくよくわからなくなっても泣かない。
System.Linq.Async // AsyncCTP - Task連携
これもRxとは微妙に独立していて、中身はIAsyncEnumerable。AsyncCTPのTaskをLinq的に扱おうとするものです。Taskだと1個しか返せないので複数返せるように、という。私はイマイチこれの必要性が分からなかったりします。ぶっちゃけIObservableで良くて、で、IObservableのほうが色々融通が利くので。なんかもう出来るから作ったし入れたよ、といったRxチームのノリがここから伺えます。フットワーク軽くて、その姿勢は大好きだけど、混乱します。
最後に、Windows Phone 7では標準搭載されていて、System.ObservableとMicrosoft.Phone.Reactiveを参照することで使えるようになります。また、標準搭載とは別に、上記のような最新版も提供されています。標準搭載と最新版の違いですが、安定度は断然標準搭載版です。MSDNにドキュメントがあるのも良い。そして勿論、標準搭載なので配信する際の容量が嵩まない。では最新版のメリットはというと、勿論、機能面では豊富。また、デスクトップ版などとも完全にAPIの互換が取れます。ただ、バグの混入率は残念ながら結構高いので安定性は若干欠けます。
Rxの使える局面って?
ハンズオンラボやセッションのタイトルがCuring the asynchronous bluesであるように、やはり非同期に対しての適用に強い。クラウド時代のデータプログラミングに非同期は避けられない、それを解決するソリューションとしてのRx。しかしC# 5.0には組み込みAsync入っちゃうしRxJSだって、jQueryに1.5から組み込みでDeferredが入るので、将来的には強い特徴にはならないのですが、未来の前に現実。特にC# 5.0なんていつだよっていう。まあ、jQueryのDeferredよりもずっとセンス良いし(よく知らないで言ってる)、C#5.0 async/awaitよりも遥かに柔軟で強力だという印象を私は持っているので、直接競合するからってoutにはならないと思ってます。
非同期じゃなくイベントのほうは、様々な側面を見せるので一概に言うのは難しい。とりあえず時間を扱うテクノロジとしてのRxは、ベストな選択です。もはや生Timerなんて使ってられません。一例を出すと
// FileSystemWatcherのChangedイベントは一度の変更で複数のイベントが発行される面倒な仕様
var watcher = new FileSystemWatcher("C:\\", "test.txt") { EnableRaisingEvents = true };
// 1秒以内に連続して発生してきたイベントは無視して通すのは最後一つだけにする
Observable.FromEvent<FileSystemEventHandler, FileSystemEventArgs>(
h => h.Invoke, h => watcher.Changed += h, h => watcher.Changed -= h)
.Throttle(TimeSpan.FromSeconds(1)) // Throttleは指定時間、値の通過がなかった場合に最後の一つを通す
.Subscribe(e => Console.WriteLine(e.EventArgs.FullPath));
FileSystemWatcherはファイルの変更を監視し、変更があった場合にイベントを飛ばしてくれる便利なクラスですが、例えば一度ファイルを保存する(変更がある)だけで、2,3個のイベントが同時に飛んできたりするなど処理が少し面倒だったりします。ググルとみんな困ってるよ。そういう場合にDateTimeを外部変数に保存しておいて比較を取るとかTimerで発火を調整するとか面倒くさいことをしなければなりません、が、RxならThrottleメソッドで一撃。
Rxではイベントの発生が時間軸上に並んでいるので、イベントに対して時間系魔法をかけることが出来ます。Throttle!Sample!Delay!TimeInterval!その他色々。未だかつてないほど時間を扱うのが容易になりました。面倒くさい印象のあったポーリングなども楽勝です。
他にイベントといったらセンサーの感知なども上げられます。Windows Phone 7に標準搭載された理由にもなるかもですが、センサーで飛んでくる大量のイベントのフィルタリング・加工にRxは実に都合が良い。また、物理デバイスがないとテストできない、あってもそもそもテストしにくいセンサー系APIですが、Rxを使うことでイベントのモック生成・差し替えが容易になります。
最後に挙げるイベント系といったら、GUI。ボタンクリックとか。これは、割とダメ。いや、ダメではないのだけど、GUIの基盤であるWPF/Silverlightががっちりとデータバインド中心に組まれているわけで、ここに無理やり割り込んでも、お互いの良さを消してしまう。フレームワークの根幹でサポートしている仕組みにRxは乗り入れられるほどのメリットを提供出来るか?というと、それは苦しいのではないかとも。Rxが標準入りすることで、WPFのフレームワーク根源からのサポートが入れば、また変わってきそう。これは未来の話。素敵な融合を夢みたい。
その他にデータの分配配信とか実行コンテキストの選択とか、メリット・特徴は色々あります。というか、なんでもかんでもが突っ込める基盤になってます。それらが渾然一体となって融合出来るというのがRxの本当の強さなのではないかと思っています。あらゆるソースをOrchestrate and Coordinateする。美しい……。
まとめ
正式になったから、それで何が変わったか、何が変わるかというとまだ不透明ではある。けれど、なにも変わらない気がします、とりあえず当面は。リリースパッケージが分かれるとかいうこともなく、なんか普通にDevLabsから引っ越ししてきました、というだけな雰囲気だし。そして、今まで通りに一月ぐらいの単位で新しいのリリースするサイクルを続けるのではないかなあ。まだ足したりなさそうだし。破壊的変更も、普通にたまにやってくるのではないかなあ。例えばIQbservableなんて、いつ名前が変わってもオカシクない。これは、QueryableObservableの略なのだけど、Observableと対比させるため同程度の長さの名前である必要があって、それでいてQbservableの本質をついた良い代案ってのは、出てこないよねえ。名前は難しい。
正式なテクノロジとして認められた、として、じゃあ今後どうなる?予想でしかないですが、まず.NET 4 SP1に入るか。これは、入らないんじゃないかなあ……。もし入ったとしても、変わらずData Developer Centerのページで最新版の開発と提供が続いていくでしょう。と、現時点でGetAwaiterが入ってたりするなど、C# 5.0 Asyncとの関係性も避けられない話なので、少なくとも.NET 4 SP1に入ったから開発終了には絶対にならないのではない。はず。.NET 5には入るでしょうが。確実に。
個人的にはWP7に搭載されている程度のものは.NET 4 SP1に入って欲しい(WP7のものは結構前のもの、リリース時期考えると当然ですが)ところなのですけれど、WP7のものとシグネチャ合わないのが出てきちゃってるのが、少々難しいかもなー、と、思うところ。一度フレームワーク本体に入れると変更が効かなくなるので、Rxチーム的にはもう少し手元に置いて弄りたいと思ってるような気がします。見ててそう思うというだけで、的外れな可能性はありますよ、あくまで私の予想なので悪しからず。
私としては、これで日本マイクロソフトにも動きが出て翻訳とか出たりしてくれると嬉しいのだけど。Rx Design Guidelinesなどは非常に重要な資料なので……。
ともあれ、使用に当たっての最大のリスク(テクノロジそのものが消滅する)というのがなくなったので、実プロジェクトに突っ込むことも十分検討できる範囲に入ってきました。実際に使ってみた、の記事が読めるようになってくと嬉しいですねえ。私は、ええと、機会があれば……。もうすぐ実際に突っ込める機会があるかもなので、なにか出せればいいか、な。サイの転がり方次第では分からないけれど。
ReactiveOAuth ver.0.2.0.0
- 2011-01-23
ReactiveOAuthを更新しました。今回よりNuGetに対応したのでReactiveOAuth、もしくはReactiveOAuth-WP7で入れられます。あとSilverlightもサポートしました。そして、盛大にバグってたのを修正しました。UrlEncodeをそのまんまの使ったのでRFC2396でRFC3986じゃないから「!」とかが含まれた文章を投稿すると死ぬ、という。あまりにも限りなく初歩ミスで、死ぬほど反省します……。
おまけに、この辺りがマズいのは出した当初から薄々感づいていたのですが、「あとで直す」とか思って延々と今まで放置していたので、もう本当に本当にごめんなさい。リリース用にzip固めるスクリプトも書いた(fsxで)し、ディレクトリ周りも整理したしで、負担なくリリースしてける態勢を整えたので、もう放置しません、今後他のプロジェクトでも。本当に、今回はあまりにも酷かったのでなんともかんともです。
一応、通信部分を以前書いたReactive Extensions用のWebRequest拡張メソッドに載せ替えたりしたりなど、中身も変えたんですが、うーん。解説する気力が折れたぽ。
とりあえずドッグフードな体制を整えるためにXboxInfoほげほげにとっとと積んでしまうかな……。
NuGetパッケージの作り方、或いはXmlエディタとしてのVisual Studio
- 2011-01-22
linq.js 2.2.0.2をリリースし、今回からNuGetでも配信されるようになりました!linq.js、もしくはlinq.js-jQuery、linq.js-Bindingsで入りますので、是非お試しを。ちなみに更新事項はちょっとBugFixとOrderByの微高速化だけです(本格的な変更は次回リリースで)。
さて、そんなわけでNuGetに対応したので、今回はNuGetのパッケージの作り方、公開のしかたについて解説します。やってみると意外と簡単で、かつNuGetいいよNuGet、と実感出来るので、特に公開するようなライブラリなんてないぜ!という場合でも試してみるのがお薦め(参照先としてローカルフォルダも加えられる)。普通に小さなことでも使いたくなります。そういえばでどうでもいいんですが、私は「ぬげっと」と呼んでます。GeForceを「げふぉーす」と呼ぶようなノリで。ぬげっと!
NuGetを使う
NuGetとは何ぞやか、大体のとこで言うと、オンラインからDLLとかライブラリをサクッと検索出来て、依存関係(これのインストールにはアレとソレが必要、など)を解決してくれた上で参照に加えてくれて、ついでにアップデートまで管理してくれるものです。Visual Studioの拡張として提供されているので、インストールはCodePlexからでもいいですが、VSの拡張機能マネージャからNuGetで検索しても出てきます。
インストールすると参照設定の右クリックに「Add Library Package Reference」というのが追加されていて、これを選択すると、トップの画像のようなNuGetの参照ダイアログが出てきます。最初NuGetが喧伝されていたときはPowerShellでのConsoleでしたが、ご覧のようにGUIダイアログもあるので安心。Consoleのほうが柔軟でパワフルな操作が可能なのですが(PowerShellを活かしたパイプやフィルタで一括ダウンロードとか)、普通に参照してーアップデートしてー、程度ならば別にGUIでも全然構いませんし。
.nupkg
NuGetを通してインストール/参照を行うと、プロジェクトのフォルダにpackages.configが生成されています。しかしこれはどうでもいいのでスルー。.slnのあるディレクトリにpackagesというフォルダも生成されていて、実体はこちらにあります。そこにはパッケージ名のフォルダが並んでいて、中には.nupkgという見慣れないものと、libもしくはContentというフォルダがあるのではないでしょうか……?
nupkgが最終的に作らなければならないもので、実態はただのzip。nupkgと同フォルダにあるlib/Contentはnupkgが展開された結果というだけです。というわけで、適当なパッケージをダウンロードして(linq.jsとかどうでしょう!)zipにリネームして解凍するとそこには……!
_relsとか[Content_Types].xmlとか、わけわからないものが転がってます。これらはノイズです。ようするに、System.IO.ZipPackageを使って圧縮してるというだけの話ですねー、恐らくこれらがある必然性はないです。ただたんに、.NET Framework標準ライブラリだけでZipの圧縮展開をしようとすると、こうしかやりようがなかったという、ただそれだけです。だから早くZipライブラリ入れてください(次辺りに入るらしい)。
大事なのは、.nuspecです。
.nuspec
.nuspec(中身はXml)に、バージョン情報やID、依存関係などが記載されています。といったわけで、自分で作らなければならないのは.nuspecです。これにパッケージしたいファイルや配置場所などの定義を記述し、それをNuGet.exeというものに通すと.nupkgが出来上がる、といった流れになっています。
nuspecの記述には、既存のnuspecを見るのが参考になるかもでしょう。但し、既存のnupkgを落として展開した結果のnuspecはNuGet.exeを通された時点で再加工されているものなので(パッケージ用のファイルの場所などの情報は消滅してる←まあ、絶対パスで記述可能だったりするので消滅してないと逆に困るわけですが)、100%そのまんま使える、というわけではないことには少し注意。
XmlエディタとしてのVisual Studio
では、nuspecを書いていく、つまりXmlを書いていくわけですがエディタ何使います?勿論Visual Studioですよね!Visual Studioは最強のXmlエディタ。異論はない。えー、マジXmlを補完無しで書くなんてシンジラレナーイ!小学生までだよねキャハハ。というわけで、補完全開で書きます。補完さえあればリファレンスなくても書けるし!IntelliSense最強説。
そのためにはスキーマが必要なわけですが、ちゃんと用意されています。NuGet Documentationの下の方のReferenceの.nuspec File Schemaにスキーマがリンクされています。CodePlexのソースリポジトリに直リンクというのが色々潔いですな。
さて、適当に新規項目でXmlを作ったら、メニューのXML->スキーマのダイアログを開き、nuspec.xsdを追加してやりましょう。
そして、とりあえずは<とでも打ってやると補完に!--とか!DOCTYPEなどなどに並んでpackageというものが。これを選択すると、一気にxmlns="http..."と名前空間まで補完してくれて!更に更に書き進めれば……。入力補完は効くし、必須要素が足りなければ警告出してくれるしでリファレンスとか何も見なくても書ける。
これなら打ち間違えでエラーなども出ないし、完璧。Xmlなんて普通のテキストエディタで気合で書く、とか思っていた時もありました。もうそんなの無理げ。VSバンザイ。なお、FirefoxのアドオンのGUI定義などに使うXULのSchemaなども当然適用出来る - XUL Schema ので、まあ、補完のないテキストエディタなんて使ってたら死んでしまうです。
なお、毎回毎回、スキーマの追加参照するのは面倒くさいという場合は、VSの標準スキーマ参照ディレクトリにxsdを直に突っ込んでおくと、楽になれます。オプション->テキストエディター->XMLでスキーマ、で場所が設定出来ます(デフォルトは %VsInstallDir%\xml\Schemas のようで)
パッケージング
nuspecのリファレンスは.nuspec File Formatに。IDとかVersionとかしか書かないし、項目も少ないしネストもないので書き方というほど書き方はないです。参考までにlinq.js-jqueryのnuspecは
<?xml version="1.0" encoding="utf-8" ?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>linq.js-jQuery</id>
<version>2.2.0.2</version>
<title>linq.js - jQuery Plugin Version</title>
<authors>neuecc</authors>
<owners>neuecc</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Linq to Objects for JavaScript. This version is plugin integrated with jQuery.</description>
<language>en-US</language>
<licenseUrl>http://linqjs.codeplex.com/license</licenseUrl>
<projectUrl>http://linqjs.codeplex.com/</projectUrl>
<tags>linq javascript jquery</tags>
<dependencies>
<dependency id="jQuery" version="[1.3.1,]"></dependency>
</dependencies>
</metadata>
<files>
<file src="../../jquery.*" target="Content\Scripts" />
</files>
</package>
といった感じ。tagsはスペース区切りで入れておくと検索の時にそのワードで引っかかる。dependenciesは依存関係がある場合に記載。対象バージョンの書き方に関してはSpecifying Version Ranges in .nuspec Filesを見て書くべし。
filesは後述するNuGet.exe(コマンドラインツール)でのパッケージング時に参照するファイルを設定。何も記載しない場合はNuGet.exeの実行時引数で解決されるので、どちらでもお好みで、という感じですが、普通はこちらに書いておいたほうが楽な気はします。
ファイル指定のsrcではワイルドカードとして*が使えます。targetのほうは、nupkgにパッケージングされた時の階層の指定。この階層の指定は非常に重要です。「Content」の下に記載すると、プロジェクト直下に対象を配置します。この例では Scripts 下に「jquery.linq.js, jquery.linq.min.js, jquery.linq-vsdoc.js」が展開されることになっています。Scriptsというフォルダ名はjQueryに合わせてあります。勿論、対象は.csでも.txtでも何でも可。
では、普通のC#でのdllのように直下には.dllとか置いて欲しくないし参照設定にも加えて欲しい、という場合はどうするかというとtargetを「lib」にします。すると自動で参照設定に加えてくれます。この「Content」とか「lib」とかってのは名前で決め打ちされてますので、そーいうものだと思うことにしませう。
残るはパッケージ化。まずNuGetのトップからDownloadsタブ(Downloadボタンじゃなく)を選び、NuGet Command Line Toolをダウンロード。このNuGet.exeに対して引数「p ファイル名」でnuspecを指定してやればnupkgが出来上がります。私はnuspecと同じ階層にexeを置いて、ついでにbatファイルに
nuget p linq.js.nuspec
nuget p linq.js-jquery.nuspec
nuget p linq.js-bindings.nuspec
とか書いたのを置いて3個のパッケージを作ってます。この辺は好き好きで。
以上が基本的な感じです。ただたんに参照設定に加える、ファイルを配置する、以上のことをやりたい場合はインストール時にPowerShellスクリプトを実行、なども出来るので色々柔軟に手を加えられそうです。また、.NET Frameworkのバージョンによって参照させるファイルを変える、といったことはフォルダの構成を変えるだけで対応で可能です。例えば.Net4の場合は lib/Net4 に、Silverlightへは lib/SL4 に、といったような感じ。
といったルールなどはNuGet Creating a Packageを見るといいでしょう。また、バージョンのフォルダ分けがワケワカランという場合は既存のnupkgを展開してフォルダ構成を見てしまうのが手っ取り早いかも。Rx-AllやNewtonSoft.Jsonなどなど。
ローカル参照としてのNuGet
nupkgは別にオフィシャルのサーバーだけではなく、個人で立てたサーバーも参照出来ます。また、それだけでなく、ただたんにフォルダを指定するだけでもOKです。
作ったnupkgはこれでテスト可能です。また、頻繁に参照に加えるものはわざわざOnlineに繋げて取ってくるの重い!という場合では一度落としたnupkgをローカルに配置してしまうのも悪くないかもです。テストというだけじゃなく、これは普通に使えますね?今まで参照設定の共通化というとテンプレート作って、程度しかありませんでしたが、これならばいい具合に自由度の効いたものが出来そうです。社内/俺々フレームワーク置き場として活用できそう。
なお、現在は、ローカル参照のパッケージは、GUIのパッケージマネージャだとバージョンが上がってもUpdatesに現れなくてアップデート出来ません。Consoleならば現れるので、ふつーにバグのよう。で、報告されていましたし修正もされていた(今リリースされているのには反映されてないもよう)ので、次のリリースでは直ってるんじゃないかと思われます。
NuGet gallery
せっかく作ったパッケージはOnlineに乗せたいよね!NuGet galleryでパッケージの閲覧・登録・管理が出来ます。よーし、じゃあパパSign Inしちゃうぞー、Registerして、と。やってもいつまでたってもInvalid Passwordと言われてしまいます。あれれ……。
現在は管理者の承認が必要なようで David Ebbo: Introducing the NuGet gallery Registerしたら、Twitterの@davidebbo宛てにapproveして!と言わないとダメぽ。私は「Hi. I registered nuget.org, id is "neuecc" . plaease approve my account.」と、スペルミスしてる適当不躾な@を飛ばしたところ数時間後にSign In出来るようになりました。いつまで認証制なのかは不明ですが、いまんところそんな感じなようです。
まとめ
オンラインで簡単にDLLをインストール出来て便利!というのは勿論ありますが、ローカルで使ってみても存外便利なものです。ぬげっといいよぬげっと。NuPackからNuGetに名前が変わったときは、事情は分かる(NuPackは名前が被ってたらしい)けど、NuGetはないだろ、いくらなんでも。と、思ってたんですが、今は何かもうすっかり馴染んだ気がします。ぬげっと。ぬぱっけーじ。ぬすぺっく。
とりあえず私は今後作るのは勿論、今まで出してきたものも、順次対応させてNuGet galleryに登録していくのでよろしくお願いしま。勿論linq.jsもよろしくお願いしま。今回の2.2.0.1は表には何も更新されてない感じですが、裏側の体制を整えてました。
F#スクリプト(fsx)により、linq.jsからAjaxMinのdllを通し圧縮化と、ついでにjQueryプラグインを生成したり、これまたF#スクリプトでリリース用のZip圧縮をワンクリックで一発で出来るようにしたり。今まで手動でやっていた(そしてミスしまくってた!リリースから10分で撤回して上げなおしとか今まで何度やってきたことか)部分を完全自動化したので、もうミスはありません。そして、自動化されたことによりリリースはミス出すし面倒なので、もう少し色々やってからにするかー、とズルズル後回しにする心理がなくなりました。多分。きっと。NuGet対応したことだしで、当分はアクティブにアップデートしていきます!
そんなこんなでF#スクリプトはぢめました。素晴らしすぎる。あとVS2010とシームレスに完全統合されたF# Interactiveがヤバい。超凄い。こんなイイものがあったなんて……。というわけでF#書きたい欲とF#について色々書きたい欲が、ので次回は実践F#書評です、多分。いや、次々回かも。とりあえず近日中には。とにかくF#は絶対触るべきですね!
おまけ
と、いうわけで、生成を自動化します。F#スクリプトでdllのアセンブリ情報を読み込んでnuspecとnupkgを生成するものを書きました。
#r "System.Xml.Linq"
open System
open System.IO
open System.Diagnostics
open System.Reflection
open System.Xml.Linq
// 同ディレクトリにNuGet.exeを置いておくこと
// mainにはnuspecへの情報登録に利用するdllを、othersにはその他のものを;区切りで
// パスはこのスクリプトからの相対パス
let main = "bin/Release/ClassLibrary4.dll"
let others = ["bin/Release/System.CoreEx.dll"; "bin/Release/System.Interactive.dll"]
let pass p = Path.Combine(__SOURCE_DIRECTORY__, p)
let xn s = XName.Get(s)
// Load Assembly
type AssemblyInfo =
{ Id:string; Version:string; Description:string; Company:string }
let getAttr<'a> (asm:Assembly) =
asm.GetCustomAttributes(typeof<'a>, true) |> Seq.head :?> 'a
let info =
let asm = Assembly.LoadFrom(pass main)
let name = asm.GetName()
{ Id = name.Name;
Version = name.Version.ToString();
Description = (getAttr<AssemblyDescriptionAttribute> asm).Description;
Company = (getAttr<AssemblyCompanyAttribute> asm).Company }
let filename = info.Id + "." + info.Version + ".nuspec"
// Build .nuspec
let nuspec =
let file src = XElement(xn "file", XAttribute(xn "src", src), XAttribute(xn "target", "lib"))
let delBlank = function "" -> "_" | x -> x
XElement(xn "package",
XElement(xn "metadata",
XElement(xn "id", info.Id),
XElement(xn "version", info.Version),
XElement(xn "authors", delBlank info.Company),
XElement(xn "description", delBlank info.Description)),
XElement(xn "files",
file main,
others |> Seq.map file))
nuspec.Save(pass filename)
// output .nupkg
new ProcessStartInfo(
FileName = pass "NuGet.exe",
Arguments = "p " + filename,
RedirectStandardOutput = true,
UseShellExecute = false,
WorkingDirectory = __SOURCE_DIRECTORY__)
|> Process.Start
|> fun p -> Console.WriteLine(p.StandardOutput.ReadToEnd())
DLLからVersionとかDescriptionとか取れてしまう、.NETのアセンブリがサクッと読み込めるF#いいわー。これだけだと情報は最低限なので、tagとかも入れたければ下の方のXElementを生成している部分に直書きで挟んでやればヨシ。スクリプトの軽快さは良いですね。なので設定というか読み込むファイルも先頭のほうで普通に直書きで指定しちゃっております。
そのまま使ってもいいんですが、ビルド後に実行するコマンドラインに指定してやれば一切の手間暇なく常にフレッシュ。おお、素敵。
XboxInfoTwit - ver.2.3.0.2
- 2011-01-21
電源OFFなのにONということになって投稿し続けるという酷い暴走していました、ごめんなさい……。というわけで直しました。
解説(言い訳とも言う)
XboxInfoTwitはスクレイピングという、普通にブラウザで表示する際のページのHTMLを解析してデータを取り出しています。今回は、HTML側でほんのちょびっと変更があって、その影響をモロに被って暴走しました。Ouch!こういう、うまくデータが取れなかった場合を想定してちゃんとエラーにしないとダメなのですね。私は今回はその辺まったく対策取ってなかったので、……といった結果になってしまいました。ほんとすみません。
一応、次からは今回のようなのが原因の暴走はなくなりました。別の原因がもとに、ってのは、うむむ……。
l2o.js 世界最速分解解説
- 2011-01-17
l2o.js、でググっても何も出てきませんね!じゃあl2o.jsって何?って話なのですが、その前に、Reactive Extensionsが12/24にChristmas Releaseと称してリリースされたわけで、RxJSにも若干更新が入っていました。
· Fix for scheduling in the Concat, Catch, and OnError operators.
· If operator can now be used without supplying an “else” case.
特に大したこともないわけでしたが。しかし、インストールディレクトリである Microsoft Cloud Programmability\Reactive Extensions\v1.0.2838.0\RX_JS を見ると、l2o.jsという見慣れないものが……?
l2o.js、つまり、Linq 2 Objects.js。ええ、ええ……。linq.jsとモロにガチにかちあいそうな匂いがします。RxJS全然更新しないなあ、やる気あんのかよお、JVGoghも辞めちゃったしー、とか思っていたのですが、その裏でこっそりとんでもないものを仕込んでいたようです。いざ出てみると、むしろやらなかったのが不思議なぐらいな。
では、使ってみましょう。ついでにlinq.jsと比較しましょう。
var array = [12, 21, 4, 5, 36, 3, 10];
// l2o.js
L2O.Enumerable.FromArray(array)
.Where(function (x) { return x % 2 == 0 })
.Select(function (x) { return x * x })
.ForEach(function (x) { alert(x) }); // 144, 16, 1296, 100
// linq.js
Enumerable.From(array)
.Where(function (x) { return x % 2 == 0 })
.Select(function (x) { return x * x })
.ForEach(function (x) { alert(x) }); // 144, 16, 1296, 100
名前空間はL2Oから。そこにRange, Repeat, FromArrayなどなどの生成子があり、あとはメソッドチェーンでクエリ演算子があり。linq.jsと完全に一致。……これはlinq.jsオワタ。
いや待て。私がlinq.jsを作ったときには既に3つぐらいLinq to Objectsライブラリはあったけれど、それのどれにも不満があったから、自分で作ったわけで、同じように書けるからといって内部のクオリティが保証されているわけではない。Rxチームが作ってるからといって生半可なものだったら許さんぞ、と、いうわけで中身を覗いてみました。
Minifyされてますが、改行/インデント整形を施すだけで十分読めます。変数難読化が入っても、構造がシンプルなので全然読める。と、いうか、そうして普通に読めるのは、linq.jsと構造がまるっきり一緒だからですが。……。一緒ですが。一緒ですねこれ。そりゃC#の忠実移植を目指して作ったlinq.jsなわけなので、l2o.jsも同じ目標に向かってるだろうから一緒になるのは当然なのですが当然すぎてlinq.jsの存在意義ががが。
中身をチラッと見てみましょう。Selectを、Minifyされていたので変数名は私の方で付け直しました。
// l2o.js
L2O.Enumerable.prototype.Select = function (selector)
{
var source = this;
return L2O.Enumerable.Create(function ()
{
var current, count = 0, enumerator;
return L2O.Enumerator.Create(
function () // MoveNext
{
if (enumerator === void 0) // initialize
{
enumerator = source.GetEnumerator()
}
if (!enumerator.MoveNext())
{
return false
}
current = selector(enumerator.GetCurrent(), count++);
return true
},
function () { return current }, // GetCurrent
function () { enumerator.Dispose() }) // Dispose
})
}
// linq.js
Enumerable.prototype.Select = function (selector)
{
var source = this;
selector = Utils.CreateLambda(selector);
return new Enumerable(function ()
{
var enumerator;
var index = 0;
return new IEnumerator(
function () { enumerator = source.GetEnumerator(); }, // Initialize
function () // MoveNext & Current
{
return (enumerator.MoveNext())
? this.Yield(selector(enumerator.Current(), index++))
: false;
},
function () { Utils.Dispose(enumerator); }) // Dispose
});
}
完全に一致。linq.jsのほうでは、MoveNextのほうに定型句のようにif(enumerator === undefined){初期化処理}を書くのが嫌だったので、そもそも別関数として隔離、Currentはどうせキャッシュを返すだけなのだから省略してMoveNextと統合させてしまえ(this.Yieldというメソッドがその辺を受け持ってる、yield returnっぽく)とか、細々としたのを入れていますが、実質的には一緒です。
なお、この辺のLinq to Objectsの仕組みは、先日紹介しましたが、JSでも一緒です。Selectなど拡張メソッは、以前の物(this = source)を内包したうえで、新しいオブジェクト(new Enumerable)を返し、GetEnumeratorによりEnumeratorを生成し、最初のMoveNextが呼ばれた時に初めて動作が始まる。
アルファ
現在l2o.jsはアルファ版というか、それ以前の状態と思われるので、今実践に投げ込むのはダメです。メソッド全然足りないしバグいっぱいあるし。具体的に挙げると、Rangeはこれだとオーバーフローしない?とかReverseが即時評価ですよー、とかDisposeが不徹底で機能してない場合がある、とか、いっぱい。
メソッドは基本的なのしかありません。OrderByや、それと集合系がごっそり抜けているので、普通に使う分にも困るぐらいなので。まあ、集合系は(Dictionaryがないので)ちょっと実装が面倒ではある……。そのために私はDictionaryを導入しています。neue cc - linq.js ver 2.1.0.0 - ToDictionary, Share, Let, MemoizeAll というのはver2.1と、つい最近からで、それまではDictionary導入してないが故にバグ持ちだったんですよね、恐ろしや……。
まあ、Script#からの生成だろうから、Dictionaryを持ってくるぐらいはお茶の子さいさいかもしれません。
まとめ
l2o.jsは、今はまだこんな風にやるよ、という骨組みを見せているだけに過ぎませんが、すぐに標準クエリ演算子は実装されるでしょう。勿論、歓迎すべきことです!私の心中が穏やかでないのもしょうがない話です!linq.jsはJSでのLinqライブラリでは最後発ですが、現在CodePlex調べでは、同種のライブラリで月々のDL数が最も多いところまで行きました。地道に続けていれば良いものはいつか認められる、という甘い幻想を少しだけ見させてもらったのですが(3/dayとか微々たるものな世界なのですけどね、そう考えるとLinqでJSというものは、今は需要が……。でも、ASP.NET MVCの普及と共に.NETerにJSでのでのLINQは、まだまだ需要が発生する余地はありますな)、公式で十分なクオリティのものが出てしまった以上は、ただある俺々ライブラリの一つとなる。
とはいっても、公式では出来ないこと、出来ない付加価値は、まだまだ幾らでも足せるはずです!現時点でも無名関数の文字列ショートカット、WSH対応、vsdoc、大量の拡張メソッド、jQueryプラグイン化とやってきたし、これらは公式では出せないはず。で、まだネタはあります。今思っているのはClosure CompilerのAdvanced Optimizations対応、任意で配列のprototype拡張の追加、ですねえ。特に後者は、ちょっとしたことには大分便利になるはずだと思っています。
あとは、もしかしたらlinq.jsがRxJSやl2o.jsに影響を与えたのではないか?と考えると、嬉しい話ですかねー。ふむふむ。ま、その辺も含めて今年のRx周りは激しく加速しそうですね。
LINQの仕組みと遅延評価の基礎知識
- 2011-01-13
新年明けましておめでとうございます。その第一弾の記事は実践 F# 関数型プログラミング入門の書評にしようと思っていたのですが、もう少し時間がかかりそうなので、せっかくの年始は基礎から考えようということで、LINQと遅延評価について最初から解説します。まあ、何をもって最初だとか基礎だとか言うのも難しいので私的な適当な基準で。つまり役に立たな(ry。なお、ここではLinq to Objects、IEnumerable<T>の連鎖についてのみ扱いますので、IQueryableについてはまた後日というか実のところ私はQueryableは全然分かってなくてやるやる詐欺が今も続いているといううがががが。
メソッドチェーン != return this
例によって単純なコードで。
var query = Enumerable.Range(1, 10).Select(i => i * i).Take(5);
foreach (var item in query)
{
Console.WriteLine(item); // 1, 4, 9, 16, 25
}
1から10を二乗したうちの先頭5つを出力という、それだけのコードです。foreachする場合のinの右側が長くなるのは個人的に好きじゃないので、わざわざ変数に置いたりするのをよくやるのですが、これは好みですかねえ。なのでリスト内包表記とかあんま好きじゃなかったりはする、記法的に。
それはともかく、ドットで繋げていると実体が隠れてしまいがちなので、分解します。
var rangeEnumerable = Enumerable.Range(1, 10);
var selectEnumerable = rangeEnumerable.Select(i => i * i);
var takeEnumerable = selectEnumerable.Take(5);
foreach (var item in takeEnumerable)
{
Console.WriteLine(item);
}
変数だらけでゴチャゴチャして余計に分からない。良く分からないものは、とりま図で。
こうなってます。中に、一つ前のものを内包している新しいオブジェクトを返しています。メソッドチェーンというと所謂ビルダー的な、もしくはjQueryなんかを想像してしまってチェーン毎に内部の状態が変化して return this するか、もしくは完全に新しいものを生成して返す(array.filter.mapしたら.filterで完全に新しい配列が生成され返って、.mapでも、的な。DeepCopyも同じようなものですか)みたいなのを想像してしまう感もあるのですが、そのどちらでもない。中に仕舞い込んで新しい包を返す。実に副作用レスでピュアい。
このことはデバッガで確認出来ます。
面白いのはSelectの戻り値の型で、WhereSelectEnumerableIteratorとなっていて、名前のとおりWhereとSelectが統合されていたりします。これは、Where->Selectが頻出パターンのためパフォーマンス向上のためでしょうねえ。面白いですがユーザー的にはあまり気にすることではないので深追いしないで次へ。
Takeの戻り値であるTakeIteratorはsourceとして中にSelectの戻り値であるWhereSelectEnumerableIteratorを抱えていて、Selectの戻り値はRangeの戻り値であるRangeIteratorを、中に抱えています。という連鎖が成り立っていることがしっかり確認できました。Visual Studioのデバッガは大変見やすくてよろしい。
遅延評価と実行
hogeEnumerableに包まれている状態では、まだ何も実行は開始されていません。そう、遅延評価!このままWhereやSkipを繋いでも、新たなhogeEnumerableで包んで返されるだけで実行はされません。ではいつ実行されるかといえば、IEnumerable<T>以外の、何らかの結果を要求した時です。それはToArrayであったり、Maxであったり、foreachであったり。
foreachを実行した時の動きを、図(但し致命的に分かりづらい)で見ると……
まず最初は最外周のtakeEnumerableに対しGetEnumeratorを実行し、IEnumerator<T>を取り出します。そして取り出したIEnumerator<T>に対しMoveNextの実行をすると、その先ではまた中に抱えたIEnumerable<T>に対しGetEnumeratorでIEnumerator<T>を取り出し、の連鎖が大元(この場合はrangeEnumerable)に届くまで続きます。
大元まで届いたら、いよいよMoveNextの結果が返されます。trueか、falseか。trueの場合は、通常は即座に現在値(Current)の取得も行うので、Currentが根本から下まで降りていくイメージとなります。あとは、どこかのMoveNextがfalseを返してくるまで、その繰り返し。今回はRangeが10個出力、Takeが5個出力なので、Rangeが5回分余りますがTakeで列挙は途中打ち切り。falseを流して終了させます。SumやCountなど値を返すものは、falseが届いたら結果を返しますが今回はforeachなのでvoid、何もなしで終了。
イテレータの実装
ついでなので、動作の実態であるイテレータも実装します。単純な、0から10までを返すだけのものを例として。
public class ZeroToTenIterator : IEnumerator<int>
{
private int current = -1;
public int Current
{
get { return current; }
}
public bool MoveNext()
{
return ++current <= 10;
}
// 必要でなければ空でもいいや、という感じ
public void Dispose() { }
// TじゃないほうはTのほうを返すようにするだけでおk
object System.Collections.IEnumerator.Current { get { return Current; } }
// Resetは産廃なのでスルー、実装しなくていいです、Interfaceからも削られて欲しいぐらい
public void Reset() { throw new NotImplementedException(); }
}
// 使うときはこんな感じでしょーか
// IEnumerator<T>利用時はusingも忘れないように……
using (var e = new ZeroToTenIterator())
{
while (e.MoveNext())
{
Console.WriteLine(e.Current);
}
}
IEnumerator<T>ですが、見てきたとおり、中核となるのはMoveNextとCurrentです、といってもCurrentはキャッシュした値を中継するだけなので、実質実装しなければならないのはMoveNextだけ(場合によりDisposeも)。
見たとおりに一行の超単純な、10超えるまでインクリメントでtrue、超えたらfalse。なんかとってもいい加減な感じで、falseだろうとMoveNext()を呼んだらCurrentの値がどんどん増加していっちゃって大丈夫か?というと、全然問題ない。と、いうのも、そういうのは利用側の問題であって実装側が気にする必要はないから。
MoveNextする前のCurrentの値は保証されていないので使うな、であり、MoveNextがfalseを返した後のCurrentの値は保証されてないので使うな、です。大事なお約束です。お約束を守れない人は生イテレータを使うべからず。Linqのクエリ演算子やforeachは、そんな他所事を考えないで済むようになっているので、それらを使いましょう。生イテレータを取得したら負けです(拡張メソッド定義時は除く、つまりライブラリ的な局面以外では避けましょう)
ちなみにStringのイテレータは列挙前/列挙後のCurrentへのアクセスで例外が飛び、List<T>は列挙前は0、列挙後も0にリセットされ、Enumerable.Rangeでは列挙後は最後の値が返る、といったように、実際に挙動はバラバラです。
実装側が守らなければならないルールは、MoveNextが一度falseを返したら、以後はずっとfalseを返し続けること。で、その観点で、このZeroToTenIteratorを見ると、実のところ全然ダメです。MoveNextがint.MaxValue回呼び出されるとcurrentがオーバーフローしてint.MinValueになって、つまりはMoveNextの結果もfalseからtrueに変わってしまいます。腐ってますね。殺害されるべき。誰がそんなに呼ぶんだよ、という感じに普段はあんま気にしないゆとりな私ですが、いえいえ、こういう時ぐらいは気にしたりします。
オーバーフローはうっかりで見落としがちなので、ヘラヘラゆとりゆとりと笑ってないで、普段から注意すべきだと自戒するこの頃。
まあ、今時はイテレータの手実装なんてする必要ないのですがね!シンプルなものならばLinqの組み合わせで実現出来ますし、そうでないものはyield returnを使えばいいので。手実装じゃなきゃダメなシチュエーションってなにかある、かなあ?
まとめ
「return thisじゃなくて新しいオブジェクトを返してる」「配列的なイメージで扱えるけれど実体はストリームのほうが近い」「デバッガ素晴らしすぎる」「生禁止」の以上四点でした。
Linq to ObjectsのJavaScript移植であるlinq.jsも同じ仕組みでやっているので、そちらのコードのほうがブラックボックスでなく、また、素直に書いているので分かりやすくお薦め、かどうかは、微妙なところですんがー。ブラックボックスになっている部分(yield returnなど)を表に出しているので(というか出さないと実装出来ない)余計分かりにくい感も。
で、基礎からのLinqといえば紹介したいシリーズが一つ。
LondonのGooglerでMicrosoft MVPでC# in Depthの著者でStack Overflowで凄まじい解答量を誇るJon Skeet氏が、BlogでReimplementing LINQ to Objectsと称して、これまた凄まじい勢いで再実装&超詳細な解説をやっているので必見です。
詳細、どころの話じゃなく詳細で大変ヤバ素晴らしすぎる。単純なサンプルコードと結果を貼ってメソッド紹介、などという記事とは一線を画しすぎるクオリティ。私もこういう記事を書いていきたいものです。こんな量とスピードの両立は超人すぎて無理ですが、今年は記事のクオリティは上げたいですね。
C# in Depth 2nd Editionはつい二ヶ月前に出たばかりで、内容も良さそうですね、読んでみたい本です。しかし私の手元には積み本がいっぱいで、とほほ。で、本といえばもう一つ、C# 4.0 Unleashedがもうすぐ(2011/1/14、明日だね)出ます。これは著者がBart De Smet氏なので大注目です。B# .NET BlogでキレキレのLinqコード、だけじゃなくILからSQLからあらゆる領域にエキスパートな凄さを見せているので超楽しみです。こちらは予約してあるので、届くのが本当に楽しみで(洋書なので届くのは月末予定のよう、F#本が読み終えた頃になる予定なのでちょうどいいー)。
Bart氏は大学時代はベルギーのMicrosoft MVP for Visual C#、その後MicrosoftのWPFチームに入り、現在はCloud Programmability Team、つまりRxを開発しているチームに入ってます。氏が入ってからIQbservableとかヘンテコなのが次々と上がってきて、ますます目が離せない状態に。PDC10ではLINQ, Take Two - Realizing the LINQ to Everything Dreamというセッションを行ってましたが、これは本当に必見。Linqの過去、そして未来を見る素晴らしいセッションでした。感動しすぎて3回ぐらい見直した。
LINQは今後「ますます」重要になるので、しっかり土台を固めて、未来へ向かおう!