linq.js入門記事を書きました

お話をいただき、@ITの.NET TIPSにlinq.jsの入門記事を、二週に渡り書きました。

このサイトでやると、アレもコレもとダラダラと書いてしまって分かりづらくなっていたのですが、記事では文字数制限などのお陰で構成がすっきり、校正してもらったお陰で文章の揺れもなく。つまるところ、ほとんど編集で助けてもらったというだけで、本当にありがとうございました。サンプルコードは、コードを見ただけで伝わるよう単純に、でもlinq.jsの威力を伝えなければならないので多少の複雑さは持たなければならない。などと思い結構悩んで作りました。

お陰様で反響も結構良かったみたいでなによりです。実績も良く分からない外部ライブラリは導入できない…… という方も、@ITに載ってるから大丈夫だよ!を説得材料(?)にできるのではないでしょうか。これを機に、是非試してみてください。

ところで幾つかの話。

メソッド名大文字

失敗した。かな……。特にTojQuery()でjQueryと見かけ上(あくまで見かけだけなんですが)シームレスに繋がっていると違和感が結構あります。以前に、jQueryとLINQの世界が視覚上切れて見えるから、むしろイイぐらいなんです、とか言ってましたが勿論ただの強がりです。この辺は今更変えにくいところで、どうしたものかな、と悩んでいるところです。

パフォーマンスについて

気になりますよね?ベンチマーク的に言えば、遅い。遅延評価の実現や豊富な機能は、速度を相当犠牲にしています。では、その遅さが許容できるほどか無視できないか。これは、卑怯な逃げ口になってしまいますが、状況次第。少なくとも普通のサイトでは問題ないレベルだと思いますし、また、ブラウザのJSはどんどん速くなっていってます。Chrome/Fx4/IE9の速さ!「許容できる」の範囲はどんどん広がっていってるのでは、と。

こういった話はC#でもそうです。LINQはベタforループより確実に遅い、が、じゃあベタforループで書くかといったら、よほどエクストリームに速度を求める場合以外は書きはしません。

Pentium3でWindows XPでIE6な奴らにも配慮する!というのも確かに美学なのですが、そうではない方向も見ないと、素敵な未来はやってこないのではないかな、って。21世紀にもなるのにループアンローリングで高速化!とかいう記事ばかりが踊る世界なんて悲しいじゃないですか。

モバイル機器のことも考えなければならないし、HTML5も控え、JavaScriptで高負荷な処理をすることも少なくないので、まだまだ時代は追いついていないけれど。それでも、私はもう少し先の未来を見ていたい……。JavaScriptがこれから先、本当に一級の言語となっていくのなら尚の事です。

Reactive ExtensionsとSQLの非同期実行

DbExecutorのパフォーマンスが十分トップクラスであることは、こないだの計測で分かりました。では次のステップはどこへ向かおう。IL生成を頑張っても、もうほんの少ししか稼げる余地は残ってない。ならば、もっと根本的なところから行こう。ええ、非同期IOを。DbExecutorは一応、拡張性を考慮してあるので継承して非同期対応しましょう。

……ところで、この記事はAsyncDbExecutorの作り方、みたいになっていますが、読み取ってほしいのは「Reactive Extensionsの使い方」です。AsyncDbExecutorは、あくまでRxの利用法のサンプルにすぎません。DbExecutorなんて使わないしー、とか思わず、その辺を念頭において眺めてみてください。

BeginExecuteReader/EndExecuteReader

SqlServerならばSqlCommand.BeginExecuteReaderメソッドが使えます。IDbCommandにはないので、対象はSqlServer特化ということになってしまいますが、まあ、それはしょうがない(非同期対応してないDBもあるわけだし)。対応させる方法ですが、まずはDbExecutorを継承してコンストラクタを弄ります。

public class AsyncDbExecutor : DbExecutor
{
    public AsyncDbExecutor(string connectionString)
        : base(new SqlConnection(connectionString))
    { }

    public AsyncDbExecutor(SqlConnection connection)
        : base(connection)
    { }

    public AsyncDbExecutor(string connectionString, IsolationLevel isolationLevel)
        : base(new SqlConnection(connectionString), isolationLevel)
    { }

    public AsyncDbExecutor(SqlConnection connection, IsolationLevel isolationLevel)
        : base(connection, isolationLevel)
    { }
}

通常のDbExecutorはIDbConnectionを受け入れるようにしていましたが、今回はSqlServer特化なのでSqlConnectionで。また、利便性を考えて生の接続文字列からも作れるようにしてやりました。IsolationLevelを受け入れるオーバーロードはTransaction処理する場合のためとなっています(別にTransactionScope使ってもいいですけどね)。あとは、非同期に対応するメソッドを作ってやれば良いだけ。

Reactive Extensions

BeginXxx-EndXxxがカッタルイのは分かりきっているので、当然のようにRxを持ち出します。

// 引数が横に長いですがほとんど省略可能なので……
public IObservable<SqlDataReader> ExecuteReaderAsyncRaw(string query, object parameter = null, CommandType commandType = CommandType.Text, CommandBehavior commandBehavior = CommandBehavior.Default)
{
    var cmd = (SqlCommand)this.PrepareExecute(query, commandType, parameter);
    return Observable.FromAsyncPattern<SqlDataReader>(
            (ac, o) => cmd.BeginExecuteReader(ac, o, commandBehavior), cmd.EndExecuteReader)
        .Invoke()
        .Finally(() => cmd.Dispose());
}

this.PrepareExecuteですが、これはDbExecutorのprotectedメソッドで、クエリ文字列や匿名型で渡すパラメータからIDbCommandを生成します。こんなこともあろうかとちゃんとprotectedにしておいて良かった。そしてキャストですが、今回はconnectionは必ずSqlConnectionで(そうなるようコンストラクタを調整してある)、戻り値がSqlCommandであることが保証されているためアップキャストしてやります。そうしないと非同期APIが使えないですから。

あとは、いつものように(?)FromAsyncPatternして、それとFinallyでcommandをDisposeしてやることを忘れないと気が効いてるかもり。利用する時は

// async=trueを忘れずに
var connstr = @"Data Source=.;async=true;Initial Catalog=master;Integrated Security=True;";

var executor = new AsyncDbExecutor(connstr);
executor.ExecuteReaderAsyncRaw("select * from sys.tables")
    .Finally(() => executor.Dispose()) // 接続のDisposeも忘れずに...
    .Subscribe(dr =>
    {
        while (dr.Read())
        {
            Console.WriteLine(dr.GetValue(0));
        }
    });

といった感じです。非同期APIはDisposeをどう仕込めばいいのかが悩ましいのですが、Rxなら簡単です、Finallyに突っ込めばいいだけ。同期APIでusingで囲むのと同じ感覚で、RxではFinallyに置いてください。非同期実行ということで、複数同時に走らせることも少なくないと思うのですが、その場合は全ての完了を自然に扱えるよう、結合して一本の流れにしてやる必要はあるでしょう。恐らくきっと。

そういえば忘れてはいけないのは、非同期APIを使う場合は接続文字列にasync=trueが必要です。これについてはADO.NET 2.0 における非同期コマンド実行によると

非同期コマンドを使用するためには、コマンドが実行される接続は、接続文字列を async=true と指定して初期化する必要があります。 非同期メソッドが接続文字列に async=true と指定されていない接続を使用するコマンドで呼び出されると、例外がスローされます。

所定の接続オブジェクトで同期コマンドのみを使用するとわかっている場合は、接続文字列に async キーワードを指定しないか、false に設定することをお勧めします。 非同期操作が有効になっている接続で同期操作を実行すると、リソースの利用率は著しく増大します。

同期 API と非同期 API の両方が必要な場合は、可能であれば別々の接続を使用することをお勧めします。 これが不可能であれば、async=true を指定して開かれた接続で同期メソッドを使用することもできます。この場合、通常どおりに動作しますが、パフォーマンスは若干劣化します。

とのことなので、少し気をつけたほうがいいかもしれません。まあ、Rx愛好家なら全てRxで非同期でやるに決まっているので(?)、別にasync=trueでも怖くありません。

SelectMany

しかし、生のDataReaderをwhileで回すとか、ダサ……。せっかくのRxなのだから値もPushで送ればいいぢゃない。

IEnumerable<IDataRecord> EnumerateSqlDataReader(SqlDataReader reader)
{
    using (reader)
    {
        // Closeされるタイミングがコントロール出来ないので、IsClosedのチェックは必須
        while (!reader.IsClosed && reader.Read())
        {
            yield return reader;
        }
    }
}

// 前に定義したAsyncRawを呼んでSelectManyするだけ
public IObservable<IDataRecord> ExecuteReaderAsync(string query, object parameter = null, CommandType commandType = CommandType.Text, CommandBehavior commandBehavior = CommandBehavior.Default)
{
    return ExecuteReaderAsyncRaw(query, parameter, commandType, commandBehavior)
        .SelectMany(dr => EnumerateSqlDataReader(dr));
}

// 使うときはこんな感じ
var executor = new AsyncDbExecutor(connstr);
executor.ExecuteReaderAsync("select * from sys.tables")
    .Select(dr => new
    {
        Name = dr.GetString(0),
        ObjectId = dr.GetInt32(1)
    })
    .Finally(() => executor.Dispose())
    .Subscribe(Console.WriteLine);

実にLINQっぽく自然になりました。yield returnを使ったのは、IObservableのSelectManyはIEnumerableも受け入れて平らにしてくれるからです。これ、Observable.UsingとかObservable.Generateを使って、Rxだけで頑張ることも可能ではあるのですが、面倒くさいしゴチャゴチャします。なので、yield returnが使えるなら、使ってしまったほうが楽。この辺はIEnumerable<T>を生成するためのyield returnがあるように、IObservable<T>を生成するためのコンパイラサポートが欲しいところ。awaitが乗ればTaskからIObservableへの変換(は基本的に容易)なので、ある程度可能になるのかなあ、と思いつつ、謂わばAsyncEnumerableになることの難しさもあるので今のところ何とも言えません。

ExecuteReaderAsyncがあればExecuteReaderAsyncRawいらないぢゃん!って感じですけれど、パフォーマンスのために非同期にするのに、SelectManyとかオーバーヘッドがあるのも嫌かなあ、と思う場合もあるかもなので、生のSqlDataReaderを返すものも残してあげるのもいいかな、とか思ったりはするところ。EnumerateSqlDataReaderのような拡張メソッドを別途定義してやれば、生のSqlDataReaderも、そう扱いが面倒というわけでもないですしね。いや、どうだろう……。

次バージョン

この調子でExecuteNonQueryやSelectなども書いていけば完成です。って、そういえばアクセサの動的生成&キャッシュの部分はinternalで外から触れない(せいぜいPrepareExecuteだけ)からSelectは書けないぢゃん。うげげ。うーん、publicにするのもどうかと思うので、InternalVisibleToで対処しようかなあ。そんなわけで、このAsyncDbExecutorは今はまだアイディア段階で内容を詰めてませんが、もっとブラッシュアップさせて、次のDbExecutorの更新時に含めたいと思っています。Rxが必要という都合もあるので、本体とは別DLLで。勿論、NuGet対応で依存解決でインストール楽々、です。

ところで本当に速いの?

うん、分かりません。ADO.NET 2.0 における非同期コマンド実行によれば

ADO.NET/SqlClient の非同期コマンド実行サポートは、実際に、本当の意味での非同期ネットワーク I/O (共有メモリの場合は非ブロッキングのシグナル通知) を基礎としています。 ご要望が多ければ、いずれ内部実装について文書にしたいと思います。 ここでは、"真の非同期" を行っており、特定の I/O 操作が終わるまで待機しているブロックされたバックグラウンドのスレッドは存在しない、と申し上げておきます。Windows 2000/XP/2003 オペレーティング システムのオーバーラップ I/O 機能と I/O 完了ポートの機能を利用し、単一スレッド (または少数スレッド) によって、所定のプロセスに対する未処理の要求をすべて処理することを可能にしています。

というわけで、まあ速いんじゃないかねえ、とは思うんですが、計らないことには分かりません。ベンチマークはAsyncDbExecutorのリリース時に、ちゃんと計ってみたいと思います。とりあえず非同期IOで万歳なNode.jsに負けてられませんからね(謎)。というのはともかく、この辺は以前にmono meetingでAzure Tableのパフォーマンスの話を聞いた時→資料:20110126 azure table in mono meeting全くサッパリだったこともあるので、ちゃんと調べたいとずっと思っていたのです(が、IOCPとかネイティブな話はさっぱり&データベースの挙動の中身も全然なので、あくまで.NETな上層のほうで…… いずれは何とかしたいのですけれど、手一杯でどうにも)。

やっぱ非同期が必須なのはサーバーサイドの話になるのですかねえ。IHttpAsyncHandlerとRx、とかそのうち書きたいのですが、そもそも私はASP.NETあんま分かりませんですよというところから始める必要があり。調べたいことがありすぎて積みタスクの山にうもれて完全死亡中。

デフォルトExecutor

最後に話は変わりますが、new DbExecutorするのに毎回コンストラクタにSqlConnection渡すのがダルいし不自然!という場合は、これまた継承して接続文字列が固定されたExecutorを用意すると良いです。

public class HogeExecutor : DbExecutor
{
    public HogeExecutor()
        : base(new SqlConnection("Data Source=hogehoge;"))
    { }

    public HogeExecutor(IsolationLevel isolationLevel)
        : base(new SqlConnection("Data Source=hogehoge;"), isolationLevel)
    { }
}

中々悪くないのではないでしょーか。残念ながらStaticメソッドのほうは使えませんが。Staticメソッドのほうは、どうも上手いやり方が考えつかなくて色々と保留中。考えてはいるのですが。

C#のMicro-ORM(Dapper, Massive, PetaPoco)について

最近、巷という名の極一部で話題になっているMicro-ORMという分野。何それ?うーん、MicroなORマッパーです。まんまですが。Entity FrameworkがUltra Hugeだとしたら、その対極にあるような。定義としては「SQL本文は手書き、マッピングは自動」だけの機能を持つもの、といったところでしょうか。Microであるために「1ファイルのみ」を入れても良さそう。少なくとも、用語の発生元っぽいDapper, Massive, PetaPocoは1ファイルのみです。

他に、シンプルめなORマッパーを志している感じなのはSimple.Dataや、そしてORマッパーじゃなくてただの実行機です!と言い張る私の作っているDbExecutorなどもMicro-ORMに入れちゃってもいいかしら?Simple.Dataは名前に反してあまりシンプルではない(MEF使ってる……)感じですが。DbExecutorは十分Microです!id:taediumさんの作られているSomaも比較的シンプルめなものに入るかしら……?

この中で注目株はDapperで、Stack Overflowのエンジニアがパフォーマンスの問題を解消するために作成したもの、ということで、超巨大サイトでの利用で鍛えられているというのは何よりも信頼への担保がある。そして、この手のO/Rマッパーにはかかせない動的コード生成によるパフォーマンス向上に関しては、パフォーマンスのエキスパート中のエキスパートであるprotobuf-netの作者 Marc Gravell氏がIL生成部分を担当しているという、凄いコンビでそりゃ色々と叶わないね、という感。

パフォーマンステスト

Dapperは親切にもベンチマークプログラムも公開しているので、リポジトリにあるもの+DbExecutor、それとDataTableを追加して計測してみました。

hand coded took 53ms
Mapper Query (buffered) took 55ms
Dynamic Mapper Query (non-buffered) took 55ms
Mapper Query (non-buffered) took 56ms
Dynamic Mapper Query (buffered) took 56ms
Dapper.Cotrib took 56ms
PetaPoco (Fast) took 58ms
DbExecutor Select took 58ms
DbExecutor ExecuteReader(Hand Coded) took 58ms Dynamic Massive ORM Query took 62ms
PetaPoco (Normal) took 62ms
DbExecutor SelectDynamic took 62ms
DbExecutor ExecuteReaderDynamic(Hand Coded) 65ms
DataTable took 83ms
BLToolkit took 85ms
Simple.Data took 90ms
Linq 2 SQL Compiled took 100ms
SubSonic Coding Horror took 114ms
Entity framework CompiledQuery took 119ms
NHibernate SQL took 127ms
NHibernate HQL took 149ms
Soma took 168ms
NHibernate Criteria took 191ms
Linq 2 SQL ExecuteQuery took 215ms
Linq 2 SQL took 671ms
NHibernate LINQ took 708ms
Entity framework ExecuteStoreQuery took 726ms
Entity framework ESQL took 728ms
Entity framework No Tracking took 966ms
Entity framework took 969ms
SubSonic ActiveRecord.SingleOrDefault took 4259ms

hand codedがExecuteReaderを手で回した手書き、「Mapper Query」はDapperのことです。複数種類があるのはオプション違い。DbExecutor(太字にしています)も同様に4種類で測っています。

結果ですが、勿論Dapperは速いんですが、DbExecutorのSelectも悪くない位置にある。というか、これは普通に高速と名乗っていいレベルの速度は出てる。というか上位陣はほとんど誤差でいいんじゃないですかというところですね、実際何回か測ると若干入れ替わったりしますし。500回のループで3ms遅くて低速とか言われたら怒ります(笑)

ところでDbExecutorのDynamic類が十分すぎるほど速いのは少し驚いたり(dynamic経由だからもっとずっと遅くなるのかと思ってた……)。この計測結果を前にすると、手動マッピングするならExecuteReaderはダルいからExecuteReaderDynamic使いますねー、型変換とか不要でずっとシンプルに書けますから。Selectが使えるシーンではSelectで、柔軟なマッピングをする必要があるシーンではExecuteReaderDynamicで、というのがDbExecutorを使う場合の幸せシナリオになりそう。また、ExpandoObjectをDataTableのRowの代わりとして使うSelectDynamicも十分な速度が出ていて、これぐらい速度出るなら普通に使っちゃえますねえ。非常に良い感じ。

何故速いのか、あるいは何故遅いのか

動的コード生成しているから速い。といっても、真ん中ぐらいより上のコードはみんなやっているのではないかしら。勿論、DbExecutorも生成しています。では何でDbExecutorは大体の場合において僅差とはいえDapperより遅いのか。これはコード生成する範囲の問題です。Dapperはクエリ用に最適化してガッツシ固めて生成・キャッシュしてますが、DbExecutorは汎用的に、Typeに対して行っているので、そこで若干の差が出ています。

最初Dapperのコード見たときは、うわあ、これは凄い差がついちゃってるのでは?とか思ったんですが、蓋を開けてみると、誤差みたいに小さな差でたいしたことなかったので、このまんまで行きます(それと言い訳がましいですがCode Contractとかのハンデも若干あるので、どの程度響いているかは不明瞭ですが)。どちらにせよ、ようするところ、DBへのアクセス速度に比べれば、その程度のチューニングは大して差が出ないということでしょう。

動的コード生成も、ILでゴリゴリじゃなくてExpressionTreeを使ったゆとり全開の生成なので、それで上位にガッツリ肉薄しているのだから、十分以上です。

まとめ

DbExecutorは普通に速い。他のと比べると気が効いていて、かつ洗練されたAPIを持っていて、非常に使いやすいので、Dapperなどと比べても負けてない。Micro-ORMの最前線で全然戦えます(但し1ファイルではないけれど!)。次のアップデートでは、クエリ時の戻りが複数になる場合の対応と、ストアドプロシージャのOUTPUTの対応を予定してますので是非是非お試しを。

と、宣伝がましくなってて申し訳ないですね……。Micro-ORM自体については、まず、Entity Frameworkなど普通のORMを使わないようなら、必需品だと思います。完全手作業でデータベース触るのは馬鹿げてる。何らかの薄いラッパーぐらいは作っているだろうけれど、Dapperよりも優れていると確信持てなければ(そして多くの場合は持てるわけがない!)、そんなものは捨ててDapperを使ったほうがいいのではないかしら。いや、DbExecutorでもいいですけどね、というかDbExecutorは良いですよ。

Entity Frameworkなどを使っている場合はどうか、というと、重量級フレームワークの欠けた部分を補ってやる感じで、良い感じに使えそうです。その辺の小回りの良さ、大きめなものと一緒に使っても上手く馴染むのはMicro-ORMならではなのではかと思います。

はぢめてのWindows Phone 7でのデータベース(Linq to Sql)

Windows Phone 7に新しいSDKが来ました!9月頃リリースという話のMangoアップデート(Windows Phone 7.1)対応SDK。まだベータですが色々触れます。そしてついにデータベースが搭載されました。というわけで軽く触ってみました。

Code First

フツーだとSQLを書いてデータベースの定義を用意しなければならないところですが、WP7でのデータベースプログラミングにおいて、SQLは不要です。と、いうよりも、そもそも使えません。データベース本体(SQLCE)や、データベースにSQLを発行するクラス(ADO.NET)はMicrosoft.Phone.Data.Internalに格納されており、Internalという名のとおり、外から触ることは出来ません。ではどうするか、というと、WP7ではデータベースはLinq to Sqlを介して操作します。

じゃあテーブル定義どうするの、リレーションどうするの、というと、それはクラスから生成します。クラスを書いて、ある程度DB的に属性を付与して、CreateDatabaseとすれば、それらのテーブルを持ったデータベースが生成されます。まずコードを。あ、そうそう、System.Data.Linqの参照が別途必要です。

public class Meibo : DataContext
{
    public Meibo()
        : base("isostore:/Meibo.sdf") // connection string
    { }

    public Table<Person> Persons { get { return GetTable<Person>(); } }
}

[Table]
public class Person
{
    [Column(IsPrimaryKey = true, IsDbGenerated = true)]
    public int Id { get; set; }

    [Column(CanBeNull = false)]
    public string Name { get; set; }

    [Column]
    public int Age { get; set; }
}

名前と年齢のあるPersonというテーブルを持つ、Meiboというデータベースを定義しました。データベースはDataContextを継承し、各Tableを持つプロパティを。そしてテーブルはTable属性とColumn属性を。IsPrimaryKeyは主キー、IsDbGeneratedは自動連番、CanBeNullはnull非許可です。Columnを付けて回るのが面倒くさそうですが、まぁ単純明快ではありますねん。

接続文字列は基底クラスに渡す形で。保存場所はIsolatedStorage内です。どうせ場所固定で弄らないでしょ?と思うので、上の例では直接定義しちゃっていますが、弄りたい場合はその辺調整で。ちなみにisostore:/です。isostore://にするとダメです(最初うっかり引っかかった)。

実際に使う場合は

// 初回実行時はデータベースを作る、これはapp.xaml.csに書いておくといい
using (var db = new Meibo())
{
    if (!db.DatabaseExists())
    {
        db.CreateDatabase();
    }
}

// Insertの例
var meibo = new Meibo();

var person1 = new Person { Name = "ほげほげ", Age = 20 };
var person2 = new Person { Name = "ふがふが", Age = 15 };
var person3 = new Person { Name = "たこたこ", Age = 23 };

meibo.Persons.InsertOnSubmit(person1); // Insertする
meibo.Persons.InsertAllOnSubmit(new[] { person2, person3 }); // 複数の場合

meibo.SubmitChanges(); // SubmitChangesまではDBへの挿入はされていない

// Selectの例(Ageが20以上のものを抽出)
var query = meibo.Persons.Where(p => p.Age >= 20);

foreach (var item in query)
{
    MessageBox.Show(item.Id + ":" + item.Name + ":" + item.Age);
}

というわけで、DBの存在を全く意識せず自然に書けます。実に素晴らすぃー。

リレーション

リレーションも勿論張れます。例はマクドナルドのバーガーの価格表で。地域で価格が違うので、Burger(バーガー名)、Price(値段)、Place(地域)の3つをBurger-Price-Placeで関連付けてきませう。

public class McDonald : DataContext
{
    public McDonald()
        : base("isostore:/McD.sdf")
    { }

    public Table<Burger> Burgers { get { return GetTable<Burger>(); } }
    public Table<Price> Prices { get { return GetTable<Price>(); } }
    public Table<Place> Places { get { return GetTable<Place>(); } }
}

[Table]
public class Burger
{
    [Column(IsPrimaryKey = true, IsDbGenerated = true)]
    public int Id { get; set; }
    [Column]
    public string Name { get; set; }

    [Association(Storage = "_Prices", OtherKey = "BurgerId")]
    public EntitySet<Price> Prices
    {
        get { return this._Prices; }
        set { this._Prices.Assign(value); }
    }
    private EntitySet<Price> _Prices = new EntitySet<Price>();
}

[Table]
public class Price
{
    [Column(IsPrimaryKey = true, IsDbGenerated = true)]
    public int Id { get; set; }
    [Column]
    public int BurgerId { get; set; }
    [Column]
    public int PlaceId { get; set; }
    [Column]
    public int Value { get; set; }

    [Association(IsForeignKey = true, Storage = "_Burger", ThisKey = "BurgerId")]
    public Burger Burger
    {
        get { return _Burger.Entity; }
        set { _Burger.Entity = value; }
    }
    private EntityRef<Burger> _Burger = new EntityRef<Burger>();

    [Association(IsForeignKey = true, Storage = "_Place", ThisKey = "PlaceId")]
    public Place Place
    {
        get { return _Place.Entity; }
        set { _Place.Entity = value; }
    }
    private EntityRef<Place> _Place = new EntityRef<Place>();
}

[Table]
public class Place
{
    [Column(IsPrimaryKey = true, IsDbGenerated = true)]
    public int Id { get; set; }

    [Column]
    public string Name { get; set; }

    [Association(Storage = "_Prices", OtherKey = "PlaceId")]
    public EntitySet<Price> Prices
    {
        get { return this._Prices; }
        set { this._Prices.Assign(value); }
    }
    private EntitySet<Price> _Prices = new EntitySet<Price>();
}

ぎゃー。面倒くさ。本来のLinq to Sqlではデータベースが先にあって、そこから機械生成でこれを作るんですが、コードを先で作るのはちょっと骨が折れます。Entity Framework Code Firstは、コードを先に作るのが大前提だけあって書きやすいように色々調整してある感じですが、WP7/Linq to Sqlは、本当にただただ手で書きますというわけで全くイケてない。

さて、リレーションはAssociation属性でつけます。また、多を辿る場合はEntitySet、一を辿る場合はEntityRefのプロパティを用意します。これがまた面倒くさ……。たいしたことはない機械的作業ですが、自動プロパティで済ませられないとウザったいことこの上なく。コードスニペットでも用意しますかねえー。

しかし苦労するだけの価値は、あります!

まずデータを用意しなきゃということでInsertを。

// Insertの例
var mcd = new McDonald();

var hamburger = new Burger() { Name = "ハンバーガー" };
var blt = new Burger() { Name = "ベーコンレタストマト" };

var kanto = new Place() { Name = "関東" };
var qshu = new Place() { Name = "九州" };
var hokkaido = new Place() { Name = "北海道" };

var prices = new[]
{
    new Price { Burger = hamburger, Place = kanto, Value = 100 },
    new Price { Burger = hamburger, Place = qshu, Value = 150 },
    new Price { Burger = hamburger, Place = hokkaido, Value = 160 },
    new Price { Burger = blt, Place = kanto, Value = 250 },
    new Price { Burger = blt, Place = qshu, Value = 230 },
    new Price { Burger = blt, Place = hokkaido, Value = 220 }
};

mcd.Places.InsertAllOnSubmit(new[] { kanto, qshu, hokkaido });
mcd.Burgers.InsertAllOnSubmit(new[] { hamburger, blt });
mcd.Prices.InsertAllOnSubmit(prices);

mcd.SubmitChanges();

リレーションを軽やかに片付けて、挿入してくれます。実に自然でイイ!それに、こういうののinsert文手書きはカッタルイですからねえ。更にSelectは

var mcd = new McDonald();

// 関東のバーガーのNameとPriceを抽出
var query = mcd.Burgers.Select(b => new
{
    b.Name,
    Price = b.Prices.First(p => p.Place.Name == "関東").Value
});

// ハンバーガー:100, ベーコンレタス:250
foreach (var item in query)
{
    MessageBox.Show(item.Name + ":" + item.Price);
}

// なお、IQueryable<T>をToStringすると手軽に発行されるSQLが確認出来る
// もう一つの手はDataContext.Logから取ること
MessageBox.Show(query.ToString());

コード上にjoinはないけど、発行されるSQLはjoinしています。手動でjoinすることも可能ですが、基本的にはオブジェクト間をドットで辿って操作します。その方が自然に書けるし、何より、楽ですもの。

DataContextのDispose

usingで括ってあげるのが礼儀正しいわけですが、WP7では実際どう考えるべきだろう。サンプル見てると、CreateDatabaseやSchemaUpdateではusingで囲んでますが、そうでない普通の操作ではコードビハインド内でDataContext使い回してるんですね。基本的にIsolatedStorageに隔離されているわけだし、画面外に出るときだけ切った繋げたすればいいのかなあ、といったふうに思いましたがどうなのでしょ。

.NET版との差分

ほとんど.NET版のLinq to Sqlと同じなのですが、若干追加があります。一つはデータベースのスキーマのアップデート。Microsoft.Phone.Data.Linq Namespace名前空間の参照で、DataContextにCreateDatabaseSchemaUpdaterが追加されます。これにより、アップデートなどによるテーブル構造の変化にも対応出来ます。もう一つは IndexAttribute Class

これらは、通常Linq to Sqlが用いられていたデータベースからのクラス自動生成じゃなく、クラスからのデータベース生成になったことにより、テーブル作りに足りていなかった面の補足と見れるかな。また、その逆で.NET版でサポートされているけれど、WP7版にはないものも幾つかあります。詳しいリストはMSDNのLINQ to SQL Support for Windows Phoneを見ればいいんじゃないかな、ということで。

学習リソース

若干の差異はあるとはいえ、Linq to SqlはLinq to Sqlなので、MSDN - LINQ to SQLを見るのが良いでしょう。また、慣れない間はWP7版ではなく.NET版で、ConsoleApplicationで挙動をあらかた確認しておいたほうが、スムースに行くかとは思います。属性貼ったりは、結構面倒だし罠もあるところですからね……。

まとめ

諸君らの愛したLinq to Sqlは死んだ!何故だ!そうしてEntity Frameworkに置き換えられる運命を辿ったLinq to Sqlですが、ここにきて華麗に復活するとは誰も予想だにしなかったところで、こういう展開は面白い。そして生SQLが使えないのは英断。縛りではあるのですが、Phoneでのアプリケーションの9.9割は、生SQLを必要とすることはないのではないか、とも。

生SQL触れるだろうと思ってWP7版も作るぜ!な勢いで用意していたDbExecutorのWP7版は永劫さようならになってしまいましたががが。DbExecutorはDbExecutorで、もう少し機能追加しますがー。

ところでMangoで、他に追加されたクラスを少し。System.Reflection.Emitが追加されました。これはILを直弄りして動的コード生成するためのクラスですが、WP7でIL生成とかヤラネーヨ。というわけでもなくはなく実は有益。シリアライザの高速化のために動的コード生成は常套手段となっているので、自分は直に使わなくても、普通にメリットは大きく。例えばJSON.NETのJSONシリアライズ/デシリアライズは、WP7版だけリフレクションを直に使ったもので見たところ遅そうでしたが、恐らく次からは.NET版と同じく動的コード生成になり、高速化されるでしょう。ORマッパーなどもそうです。そう、Linq to SqlでもMetaAccessorクラスなどの辺りを覗いてみれば、ILをEmitしているコードが見えます。

そういえばLambdaExpressionもCompile出来るようになりました。が、AssignやLoopなどは搭載されていません、ぐぬー。コード生成したい人はExpressionTreeでお手軽、ではなく、まだまだILGeneratorでEmit頼りしかなさそうです。更に言えばExpressionVisitorも入っていませんね。SL4に近くなったけれどSL4とは言えない、WP7はWP7としか言いようのないAPIになってまいりました。

基礎からのCode Contracts

23日にCode Contractsについてのセッションを行いました。

ufcppさんのレポートとセッション資料は第7回日本C#ユーザー会 勉強会レポート - 日本 C# ユーザー会に。Code Contractsを説明する場合、通常は背後にあるDesign By Contractの説明をしてから流れると思うのですが、今回はufcppさんが前の時間で受け持ってくれたので、その辺は完全スルーで.NET上のCode Contractsの話のみにフォーカスしています。

標準入りしているようだけど何なの?→実際は標準入りとは全然言えません というところから入って、主眼はバイナリリライター、ということで、セッションでは.NET Reflectorを片手にどのようにリライトされるかを見ていきました。どう展開されるのかをそうして確認すると、仕組みが理解しやすいのではないかと思います。Reflector有料化ということで、代替も色々出てきているようですが、私はReflector使い続けますね。他のはまだ低速だったりと色々引っかかるところが多いので。それとまあ、恩返しというか、今までお世話になっていますし。

Code ContractsはDevLabsの中でも、Axumは死亡が確定(Blogに開発チームオワタと書いてあった、ページから消えるのも時間の問題?)だし、Dolotoは明らかに開発止まってて何故残り続けているのかが分からないぐらいだし、というわけで最古株となっていますね。GT先輩いつ卒業するの!(やっとしました!)という感じな某車ゲーを少し思い起こしたり。卒業出来る日は来るのでしょうか。

それにしてもDevLabsはTC Labsばかりとなってしまい、何かツマラナサも感じてしまうような。というかtcのロゴの3って、最初にリリースされたSho, Dataflow, Dryadと3つだから3なのかと思ってましたが、最近Solver Foundationも入ってしまって4じゃねーか、という感。ていうかSolver Foundationは結構イケてるロゴがあるので、別にTCを冠しなくても良かったような。DryadはDryadで、'Dryad' becomes 'LINQ to HPC' !だそうで、色々整理しきれてない感。

ところでスライド作りは結構楽しくはあるんですが、やっぱ大変ですねー。コードはコンパクトでなければならないし、全体的にしっかり流れが整ってなければならないし。かなり考えますが、そのお陰で、私の普段のだらだらブログ記事よりは分かりやすさアップしてるかな?というところです、前回のRxのスライド - Reactive Extensionsで非同期処理を簡単にもそうでしたが。

Reactive Extensionsで非同期処理を簡単に

すまべん特別編「Windows Phone 7 開発ブーストアップ」@関東にて、Reactive Extensionsの概要と、特に非同期を中心に話しました。以下、発表資料になります。

当初は初心者向け、と思ったんですが、どう見ても一回触ったことのある人向けですねこれ……。Rxを触ったことない人は、よくわからないけど普通に書くと大変なのがスッキリして何だか凄そう、触ってみようと思ってもらえれば。Rxを既に触っている人には使いこなしのTipsとして役立てて貰えればと思います。

はい、Ustreamも残っています。マイクがなかったからという言い訳をしますが、声が全然入ってないですね、声入ってないということは会場でもモゴモゴーという感じで聞き取りにくかったはずで、すみません。それと、「まぁ」言い過ぎ。繋ぐ言葉を捜す枕詞として使いまくりで、うわちゃー、という感じ。慣れてないというか、こういうの(ほぼ)初めてで全然分かってなかったんですが、これを活かして次も頑張りたいです。(Usreamで自分の発表が自分で後から見れるのは自分が嬉しい(笑))。スピーカーできて楽しかったです。機会をくれたすまべんの方々に感謝します。

……こういう機会がないと中々まとめないよね、というのもかなりあったり。合成系のメソッドの図はずーっと書こうと思っていて、書いてなくてこのセッションが初めてです。IObservableは時間軸に乗っているという話もこれが初めて。Twitterでボソッと書くだけじゃなくて、しっかりブログにまとめるようにならないといけないなぁ。

Reactive Extensionsによる非同期クエリ

InfoQ: Future、性能、依存性の低減など多くの改善がされたAkka 1.1リリースから「- Futureは完全にモナドになった。したがってfor内包表記を利用できる。」。リスト内包表記は、ようするところLINQなわけなので、では、とりあえずC# + Reactive Extensionsで。

// 非同期に対するLINQ(map, filter, etc...)
var asyncQuery =
    from a in Observable.Start(() => 10 / 2)
    from b in Observable.Start(() => a + 1)
    from c in Observable.Start(() => a - 1)
    select b * c;

// 非同期のまま実行したいならSubscribe
var canceler = asyncQuery.Subscribe(Console.WriteLine);

// 実行をキャンセルする場合はSubscribe時の戻り値をDispose
canceler.Dispose();

// 同期的に待って値取得したいならFirst
var result = asyncQuery.First();

Rx抜きで、TaskのContinueWithで↑を書くのはカッタルイ。また、Rxでもメソッド構文でSelectManyを連鎖でも辛い。何故か、というと、aの値をcの部分で使えないから。メソッドチェーンの形だと、どうしても一つ手前の値しか持ち越せない。そこで、クエリ構文が活きます。また、LINQであるが故にクエリ構文が使えるRxの嬉しさ。

じゃあ、調子にのってFutures (Scala) — Akka DocumentationをRxで書き換えてみようかしら。同じような内容としては以前にRxを使って非同期プログラミングを簡単にという記事でTaskと比較していたのでそちらも参照を。

// directly
var f1 = Observable.Return("Hello World");

// LINQが使える
var f2 = f1.Select(x => x.Length);

// Subscribeまで実行が遅延されるのでSleepしないよ
var f3 = Observable.Defer(() =>
{
    Thread.Sleep(1000);
    return Observable.Return("Hello World");
});
var f4 = f3.Select(x => x.Length); // まだ実行されないよ
var result = f4.First(); // ここで実行

// Observableの連鎖はSelectManyで
var f5 = f1.SelectMany(x => f3);

// SelectManyはクエリ構文のfrom連打でも置き換えられる
var f6 = from a in Observable.Return(10 / 2)
         from b in Observable.Return(a + 1)
         from c in Observable.Return(a - 1)
         select b * c;

と、この辺まではいいんですが、Composing Futuresが何やってるのかよくわからないので(Scala知識ゼロですみません)、眺めながらAsync CTPでも持ち出します。

async void HomuHomu()
{
    var f1 = Observable.Return(100); // IObservable<int>
    var f2 = TaskEx.FromResult(200); // Task<int>

    var a = await f1; // 何気にIObservable<T>はawait出来る
    var b = await f2; // 当然ですがTask<T>もawait出来る
    var result = a + b; // 300

    // じゃあObservableが幾つも値持ってる場合は?
    var f3 = new[] { "homu", "mado" }.ToObservable();
    var c = await f3;
    Console.WriteLine(c); // "mado"

    // つまり、完了まで待って(OnCompleted)、最後の値が取得される

    // ところでObservable.Return = TaskEx.FromResultなわけですが
    // 以下の3つも同じと捉えていいです
    Task.Factory.StartNew(() => 100);
    TaskEx.Run(() => 200);
    Observable.Start(() => 300); // つまりfunc自体は即時実行
    
    // こちらも等しい(実行が遅延される)
    var t = new Task<int>(() => 100);
    var o = Observable.ToAsync(() => 100);
    // 実行するには
    t.Start();
    o.Invoke(); // もしくは o() ←ただのデリゲートなので

    // ToAsyncでは実行時に引数を渡すことも可能
    var o2 = Observable.ToAsync((int arg) => arg * 2);
    o2(1000).Select(x => x).Subscribe(Console.WriteLine);
}

雰囲気で何となくそうなのだろうと思いつつ、よくわからないので、適当に解釈しながら次。

// IObservable<T>はそのものがリスト状態とも言えるので、
// 複数値を持てるし、LINQなのでSelectしてAggregateも出来る
var futureSum = Observable.Range(1, 1000)
    .Select(x => x * 2)
    .Sum();
    
var sum = futureSum.First();

とりあえずこの辺で(特に言いたいことはない)。全く読めないとこういう時辛い。ActorとReactiveの関係とは、とか、見えそうな見えないような気持ち悪さが脳に渦巻いていて、勉強したいところです。F#で。

上の話とは関係なく告知

二件ほどお話を頂いたので、セッションします。まず、2011/05/21(Sat)にすまべん特別編でRxについて。内容はRx全般になるので、WP7ではなくても適用出来る話になります。

Rxの多くの機能のうち非同期に絞って、かつ、初心者向けに説明しますので、Rxって何それ食べれるのという感じでも全然大丈夫です。また、既に触っている人も、割とためになるTipsが得られるのではないかなと思いながら資料作成中。そうなるよう頑張ります。なので、是非聞きに来てください。セッション資料は、通信環境があればセッション終了後即座に上げるつもりです。なければまた後日で。Ustreamとかもあるのかな?あれば、そちらでも。

もう一件、5月23日(月)にC#ユーザー会でCode Contractsについて。

背景であるDbCなどについてはufcppさんが説明してくださるので、私はCode Contractsとして実装されていることを、Reflectorでこうリライトされるんですねー、とか見ながらデモ中心に、「一から使ってみよう」といった内容にしようと思っています。Code Contracts…… 名前だけなら聞いたことがある、いや、名前も聞いたことない何それ、ぐらいからが対象なのぜ、是非どうぞ。もう使っている、という人には物足りないかも(むしろそこは私が教えて欲しいもがもがもがもが)。

どちらも、まだ参加申し込み出来るようなので是非聞きにきてください。

Reactive Extensions RC0リリースによる変更点

DevLabsの実験的プロジェクトからData Developer Centerへの正式プロジェクトとして昇格したRxですが、ついにDevLabsのページ自体が消滅(リダイレクトされる)し、いよいよ実験的なノリは一段落し、正式なプロジェクトとしての道を歩み始めたようです。その手始めとして、馬鹿デカい破壊的変更がやってきました。……っていきなりなんじゃそりゃ。

今回の変更はRC0、そしてStableであると銘打たれ、(今度こそ)APIの破壊的変更はないものと思われます。きっとAPIを変更するなら本当の本当に最後のタイミングだから、ということなのでしょうね、変更の嵐は。そんなわけで、DLLの分け方が変わってるし、名前空間も全部変わってるし、メソッド名もばかばか変わってるし、メソッドシグネチャも変わってるし、なくなったのもあるし、大量すぎて書ききれないほどに変更点がある。

しかし、本当の本当に安定版の始まりなので、つまり、学ぶなら今からが正に最適ということです!また、基本的な使い方が変わったわけではないので、既存の知識は生かせますしコード自体もそのままでも大体は行けます。大体は。

詳しい変更内容自体はフォーラム New Release: Reactive Extensions v1.0.10425 に書かれています。こういうのはフォーラムじゃなくてBlogのほうでちゃんと告知してください……。リリースから半月近く経つのに、まだBlogのほうは更新されてないという。

Rxの入手方法・パッケージ・DLL内容について Part2

以前にReactive Extensionsを学習するためのリソースまとめとしてまとめましたが、そのうちDLL内容がまるっと変わったので、そこの部分を修正します。なお、学習リソースについては変りないので、以前のまとめ記事をそのまま参照してください。また、Windows Phone 7に標準搭載されているものは(当然)変わりはありません。最近WP7本体のアップデートにコソッと紛れて更新(バグフィックス)されたようですけど。

Reactive ExtensionsのGet itからDownloadするといいでしょう。色々書いてありますが、2のDownload the Reactive ExtensionsからRx for all Platformsを選べばよいかと思います。

StableとExperimentalがあるように、安定版と実験版に分かれています。そして現時点ではそのページのExperimentalをクリックしてもExperimentalは手に入りません(なにそれ……)。Experimentalが欲しい人はMicrosoft Download Center: Search ResultsのExperimental Releaseから入手するといいでしょう。バージョン番号は、Stableは1.0.10425、Experimentalは1.1.10425になっています。

けれど、何だかんだで更新頻度が高いので、NuGet経由での利用が一番お薦めです。

が、NuGetの画面は新旧入り乱れていて何を入れていいか分からないカオスになっていたりして。説明すると、Rx-Mainとか、名前がRx-になっているものが新しいもので選ぶべきもの。Reactive Extensions -のものは古い残骸なので無視してください。また、NuGet経由で入るものはExperimentalのほうになります。

さて、今回からDLL類の分類がばっさり変わりました。

  • System.Reactive (NuGetではRx-Main)

以前あったCoreExは消滅し、コアコンポーネントはSystem.Reactiveのみとなりました。また、名前空間も全てSystem.Reactive以下に集められていて、例えば今までObservableクラスはSystem.Linqでしたが、今回よりSystem.Reactive.Linqに変更されました(拡張メソッドの利用に名前空間の参照は必須なので、この名前空間のusingは忘れずに)。

  • System.Reactive.Windows.Threading (NuGetではRx-WPF/Rx-Silverlight)

WPF/Silverlight向けでDispatcherに対するObserveOnとSubscribeOnのオーバーロードが追加されています。また、Dispatcher.CurrentDispatcherに対してObserveOn/SubscribeOnを行うObserveOnDispatcher/SubscribeOnDispatcherの利用もこのDLLの参照が必要になりました。それとDispatcherに対してBeginInvokeして実行するスケジューラDispatcherSchedulerが追加されました。

WPF/SilverlightでRxを使う場合はこれの参照は必需と思われます。NuGetを使う場合は依存の解決で、これを選択するとRx-Mainも入れてくれるので、こちらからInstallすると良いでしょう。

  • System.Reactive.Windows.Forms (NuGetではRx-WinForms)

WindowsFormsのControlに対するObserveOnとSubscribeOnのオーバーロードが追加されています。それとControlScheduler(Controlに対してBeginInvokeして実行するスケジューラ)。それだけです。というわけで、その名の通りWinFormsで使う場合だけ、あると便利。

  • System.Reactive.Providers (NuGetではRx-Providers)

Qbservableが収納されています。QbservableはIEnumerableに対するIQueryableみたいなもので、式木からObservableを生成するためのもの。今のとこ有効活用されている例も人もいないと思われます。(というかよく正式リリースにも生き残ったものだ、ぐらいの)。ちなみにQueryable Observableの略だそうで。QBみたいなものだと思えば可愛い!

例えばLinq to Twitterを非同期しかないSilverlightでやるなら、これを使うのが適切でしょう。現状だとコールバックでどうだのという格好悪い仕組みなので。(但し、System.Reactive.Providersは現状ではDesktop版にしか同梱されていませんが)。あとは公式の例として挙げられているWQL Provider。WMIに対するSQLで、クエリ結果はイベント(つまりRx)になる。非常に都合よくQbservableに当てはまるようになってますね。なってるんですが、そう都合よく当てはまるのはこれぐらいしかないのではないか、感もあったり。

いや、むしろ全て非同期なら全部Rxでいいんですよぅー、to SqlだってSqlCommandのBeginExecuteReaderでやればIQueryableじゃなくてIQbservableの出番なんですよぅー。……とはいっても、誰がやるかって話ですね。

  • Microsoft.Reactive.Testing.dll (NuGetではRx-Testing)

ユニットテスト用のモック生成クラス群。使いやすさ的には個人的にはちょっと微妙で、今一つ上手く活用出来なくて色々見送り中。

FromEvent/FromEventPattern

BufferWithCount/BufferWithTimeが統合されてメソッド名がBufferになった、程度の変更は割とどうでもいいのですが、Rxの中核であるFromEventに大きな変更があったのは見逃せません。簡単に解説します。

今までFromEventというメソッド名だったものはFromEventPatternに変わりました。また、戻り値がIEventからEventPatternというものになりましたが、中身はプロパティにSenderとEventArgsを持つという、ほとんど同じものなので、感覚的には一緒です。今までの私の記事や古いウェブ上の記事を見る際にFromEventが使われていたら、それはFromEventPatternに置き換えてください。そうすれば、そのままで動きます。

では新しく新設されたことになるFromEventは何なのかというと、よくわかりません:) そのうち使い方の説明とか出てくると思うのでそれ待ちで……。いやすみません。

ところでInteractiveはどうしたの?ClientProfileは?Asyncは?

死にました。というのもアレですが、とりあえず先行きは不透明です。少なくともStableに同梱されることはないそうです。Experimental側でのリリースは、一応計画はされているようですが、現状は同梱されていません。どうなるんでしょうかねえ……。Interactiveは欲しい人はNuGetに古いのが残っているので、それを使えば、ですね……。

Experimental

さて、今のところ、どのメソッドが実験的とされているのか、見てみましょう。幸いExperimentalAttributeでマークされているので、確認はコードで容易に出来ます。

typeof(System.Reactive.Linq.Observable)
    .GetMethods()
    .Where(mi => mi.GetCustomAttributes(typeof(ExperimentalAttribute), false).Any())
    .Select(mi => mi.Name)
    .Distinct()
    .OrderBy(s => s)
    .ToList() // Interactiveが消滅してしまったから...
    .ForEach(Console.WriteLine);

// 実行結果
Case
Create // 追加のオーバーロードのみ、通常のはExperimentalではない
DoWhile
Expand
For
ForEachAsync
ForkJoin
GetAwaiter
If
IsEmpty
Let
ManySelect
Remotable
Start // 追加のオーバーロードのみ、通常のはExperimentalではない
While

あまり大したものは入ってないようなので、そんな気にすることもないですね。Expandは是非入れてきて欲しいところなのだけど。CreateやStartのオーバーロードはかなりややこしい事になっているので、実験的扱いなのは納得。

ReactiveOAuth ver.0.3.0.0

そんな大移動があったわけでReactiveOAuthも動かなくなってしまった。というわけで更新しました(WP7版の人は気にしなくてもいいです)。

機能は変わってなし。とりあえず最新版のRxで動くように、というだけです。コードが、とにかく名前空間が変わったので全部書き換えて、かなり面倒……。そして一部のメソッドは名前が変わったので、WP7版と完全にコードを共有していたので発狂。ifディレクティブでメソッド呼び出し部分をひたすら書き換え、などというのは見通しも悪いし格好悪いしで最悪なので、別の方法として、WP7側に拡張メソッド作ってコード上の互換を維持するようにしました。

public static class ObservableForCompatible
{
    // 本体のコードはRx RC0に合わせて、WP7側だけ拡張メソッドで同名のものを作って対処
    public static IObservable<IList<T>> Buffer<T>(this IObservable<T> source, int count)
    {
        return source.BufferWithCount(count);
    }
}

他にも挙動が若干変わってるのがあって原因掴むのに泣きそうになったりとか、思った以上に大変だった……。Stableと銘打ってるのに、次にこのクラスの大変更があったらさすがにブチ切れます。今回は、まあ、許す。

Reactive Extensions Extensions(Rxx)

コミュニティから面白いライブラリも上がってきています。

Rx拡張メソッド集。C# 3.0の時も俺々拡張メソッドライブラリがいっぱい出てきましたが、そのノリですね。でも実際、Rx自体は原始的な機能のみなので、非同期処理とかイベント処理にフォーカスする場合は、もう一つ上の層で軽くラップしたライブラリは間違いなく必要だなと思っていますので、こういうのはいいな、と。私自身も非同期処理はReactive Extensions用のWebRequest拡張メソッドとして、結構ガッツし仕込んだものを使い回していて(ReactiveOAuthやUtakotoha の内部はこれ)かなり重宝しています。余裕が出たら、このRxxプロジェクトにJoinしたいな、と思ってます。

Rxの本

オライリーから出ているProgramming C#でお馴染みのJesse Libertyと、共著者としてReactiveUIというRxでWPFのGUI面をサポートするライブラリを作成しているPaul Betts(Microsoft Office Labsに所属)による、Rxの本が今年の秋頃に出る予定です。

執筆陣が豪華だしページ数も現時点amazon表示で300ページと、立派な仕上がりを予感させます。私は予約したよ!

まとめ

今回こそStableなはずなので、ようやーく人に自信を持って薦められるようになりました!いやマヂで。API的にも多分、じゃなくて絶対安定したわけなので、飛び込むなら今!です。

ところで本題とは関係ないんですがスマートフォン勉強会 - すまべん特別編「Windows Phone 7 開発ブーストアップ」@関東でWP7+Rxのセッションをします。入門編として、主に非同期処理にフォーカスして、今すぐコピペで使ってコールバックを撲殺しよう、といった内容を考えていますので、是非聞きに来てください。

DbExecutor ver.2 - C#での生SQL書き補助ライブラリ

データベース用のどこにでも転がっていそうなシンプルなユーティリティ、Part2。全面的につくり直しました(Part1もありました、一年前に公開してます、が、正直イマイチだった!)。

何でこの時期に?というと、睨んでいるのはWP7にSQLCEが乗るという話、です。まあ、Linq to Hogeが積まれるようなので、イラネーだろという話はあるのですが!あるのですが、それでも生SQLを使わざるを得ないシチュエーションは出てくるはずで、そのために、今のうちに作っておく/作りなおしておこうかと。まだWP7でどういう形で載るのか分からないので、今は普通に.NET 4 Client Profile用です。WP7へはSDKが出次第、すぐに対応させるつもり。

さて、どんな場合がターゲットかというと、生SQLを発行したい場合向け。大抵は軽くラップしたの作ってると思うんですが、そういう軽めのユーティリティとしてはベストなものを提供したいな、と考えました。この手のもので一番なのはEnterprise LibraryのDataなのでしょうか。確かに立派なんですが、見た感じ高尚すぎてお口に合いません(個人的にはかなり嫌いな雰囲気……)。古いものがベースのまま拡張している感がありありなところも見えるので、余分な贅肉をバッサリ切り落として極限までライトウェイトにしました。

ExecuteReader

基本的にはADO.NETのシンプルなラッパーです。生SQLを書いて実行を、少しだけ楽にサポートするという、それだけのものです。単純明快にIDbConnectionからインターフェイスだけで生やしているので、Sql Server, Sql Server Compactはもとより、Entity SQLでも動きます。SQL Azureもいけるかな。依存は極力廃したので、MySqlやOrcale、SQLiteでも(多分)動きます。但しプレースホルダは名前付きでないとダメなので(順序依存のものは動作を保証しません)、Accessとかはきっとダメ。

とりあえず、何もかぶせてないものとの比較で例を。DBは、例なので何でもいいんですが、Productsテーブルに、ProductNameとQuantityPerUnitとSupplierIDとUnitPriceというカラムがある。といったような代物です。ようは、Northwindですが。

// こんなデータ格納クラスがあるとして
public class Product
{
    public string ProductName { get; set; }
    public string QuantityPerUnit { get; set; }
}

//

var connStr = @"Data Source=NORTHWIND"; // Northwindサンプルから...

// 何もかぶせてない素の状態だと結果セットを取得するためのListを予め作ってAdd
// コマンドの準備も面倒、結果セットを回すのも定型句なのに行数沢山取ってシンドイ
var products1 = new List<Product>();
using (var conn = new SqlConnection(connStr))
using (var cmd = conn.CreateCommand())
{
    conn.Open();
    cmd.CommandText = @"
        select ProductName, QuantityPerUnit from Products
        where SupplierID = @SupplierID and UnitPrice > @UnitPrice";
    cmd.Parameters.Add(new SqlParameter("SupplierID", 1));
    cmd.Parameters.Add(new SqlParameter("UnitPrice", 10));

    using (var reader = cmd.ExecuteReader())
    {
        while (reader.Read())
        {
            var p = new Product
            {
                ProductName = (string)reader["ProductName"],
                QuantityPerUnit = (string)reader["QuantityPerUnit"]
            };
            products1.Add(p);
        }
    }
}

// DbExecutorを使うとパラメータは匿名型で生成
// 結果はIEnumerable<IDataRecord>からLinq to Objectsでさらさら書ける
var products2 = DbExecutor.ExecuteReader(new SqlConnection(connStr), @"
        select ProductName, QuantityPerUnit from Products
        where SupplierID = @SupplierID and UnitPrice > @UnitPrice
        ", new { SupplierID = 1, UnitPrice = 10 })
    .Select(dr => new Product
    {
        ProductName = (string)dr["ProductName"],
        QuantityPerUnit = (string)dr["QuantityPerUnit"]
    })
    .ToArray();

そのまんまだと、ただ結果取りたいだけなのに、物凄く行数を使うんですね。コマンドパラメータの追加なども大変面倒くさいし、結果セットの受け取りも大変。DbExecutorでは、この二つに対処するため、コマンドパラメータは匿名型で渡せるように、結果はIEnumerable<IDataRecord>の形で受け取ることができます。そのため、Selectした後は、ToArrayするなり、Linq to Objectsの操作にそのまま流れることが可能です。

この手のユーティリティでたまに見かける、SqlDataReaderだけを返すものは、あまり意味ないのではかな。やることなんて99%、グルッと回して行の値を取ることなので、それなら、そこまで面倒見てあげよう。IEnumerable<T>を返されても扱いようがなかった石器時代と違って、今はLinqがあるので、yield returnで返す。Stream的なものは全てIEnumerable<T>に変換する。そして全部Linqで処理する。それが現代の常識(キリッ

なお、基本的には静的メソッドで(DbConnection, SQL文字列, パラメータ(匿名型))という形でメソッドを呼びます。DbConnectionは実行完了時にDisposeするため、usingで囲う必要はありません。

ExecuteReaderDynamic

C#3.0の鉄則がストリームっぽいものはyield returnで返す、ならば、C#4.0の鉄則は、動的っぽいものは全部dynamicで返す。ことです。実に色々と楽になります。

// ExecuteReaderDynamicはIDataRecordをdynamicで包んだものを列挙する
// dynamicであることにより、カラム名のアクセスが自然に、また、キャストが不要になる
var products3 = DbExecutor.ExecuteReaderDynamic(new SqlConnection(connStr), @"
        select ProductName, QuantityPerUnit from Products
        where SupplierID = @SupplierID and UnitPrice > @UnitPrice
        ", new { SupplierID = 1, UnitPrice = 10 })
    .Select(d => new Product
    {
        ProductName = d.ProductName,
        QuantityPerUnit = d.QuantityPerUnit
    })
    .ToArray();

ExecuteReaderのものとの違いはSelectの箇所だけです。ExecuteReaderDynamicはIEnumerable<dynamic>を返し、そのdynamicの中身はIDataRecordをDynamicObjectで包んだものです。このことにより、見た目が更に自然に、また、煩わしい型変換をdynamicが自動でやってくれるので、キャストが不要になり、書くのがとても楽になります。

更に嬉しい特典はデバッガでの表示。

列挙中にブレークポイントを張って観察すると、動的ビューでカラム名と値、型が見えるようになります。(おっと、これはカラム名にスペースが入っているので動かないというツッコミが、いやまあ、はは……)

簡単な出力ぐらいならSelectを通す必要すらないです。

var query = DbExecutor.ExecuteReaderDynamic(new SqlConnection(connStr), @"
    select * from Products where UnitPrice < @UnitPrice
    ", new { UnitPrice = 20.0 });

foreach (var item in query)
{
    Console.WriteLine(item.ProductName + ":" + item.UnitPrice);
}

大変シンプルに書けますね。C#はLLですから!

ExecuteNonQuery/ExecuteScalar

ExecuteNonQueryやExecuteScalarも同じノリで行けます。

// パラメータはプロパティから取得するので、別に匿名型でなく普通のクラスでも可(insertやupdateで便利)
DbExecutor.ExecuteNonQuery(new SqlConnection(connStr), @"
    insert into Products(ProductName, QuantityPerUnit)
    values (@ProductName, @QuantityPerUnit)
    ", new Product { ProductName = "何か", QuantityPerUnit = "QUQNQUN" });

// パラメータが不要な場合は省略可
var serverTime = DbExecutor.ExecuteScalar<DateTime>(new SqlConnection(connStr), @"
    select GetDate()");

パラメータは匿名型でなくても、普通のクラスでも可なので、UpdateやInsertの際に便利に使えるかと思います。クエリ文の@に書かれてないパラメータは無視されるので、クラス側に余計なパラメータがある分には問題ありません。

Select/SelectDynamic/Insert/Update/Delete

今までの4つは、IDataReaderの基本的な操作をラップしただけのものでしたが、他に、少し手の入ったメソッドを5つ用意してあります。メソッド名通り、Select/Insert/Update/Deleteをシンプルに行うためのものです。

  • Select

select文の結果をIDataRecordを触ることなく、指定した型に移します。

// IEnumerable<T>を返し、カラム名とプロパティ名を自動でマッピングする
var products4 = DbExecutor.Select<Product>(new SqlConnection(connStr), @"
        select ProductName, QuantityPerUnit from Products
        where SupplierID = @SupplierID and UnitPrice > @UnitPrice
        ", new { SupplierID = 1, UnitPrice = 10 })
    .ToArray();

O/Rマッパーというには烏滸がましいというか別にそんな大仰なものではなく、単純にselect文をオブジェクトに転写するという、それだけ。それだけなんですが、それだけのシチュエーションって結構多いですよね?これだけで、生SQLの苦痛が随分と癒される。そう、生SQLを書くのが嫌なんじゃなくて、最後にオブジェクトに手作業で対応付けるのが嫌だったんだよ、と思える程度には。

パフォーマンスもほとんど問題ありません。一回目の実行時にデリゲートの動的生成+キャッシュを行い、全てリフレクション経由ではなくデリゲート経由のアクセスを行うため、十分高速です。基本はneue cc - Expression Treeのこね方・入門編 - 動的にデリゲートを生成してリフレクションを高速化で書いたものですが、若干これ向けに修正してあります。

そうそう、今までのパラメータの匿名型渡しも同様にデリゲート生成していますので、匿名型渡しであることによる速度低下は全くありません。

  • SelectDynamic

select文の結果をExpandoObjectに移します。

// IEnumerable<dynamic>で、dynamicの中身はExpandoObject
var products5 = DbExecutor.SelectDynamic(new SqlConnection(connStr), @"
        select ProductName, QuantityPerUnit from Products
        where SupplierID = @SupplierID and UnitPrice > @UnitPrice
        ", new { SupplierID = 1, UnitPrice = 10 })
    .ToArray();

SelectDynamicもExecuteReaderDynamicも、共にIEnumerable<dynamic>なのですが、ExecuteReaderDynamicのdynamicは、あくまでIDataRecord、というよりもIDataReaderをdynamicでラップしたに過ぎないため、Selectで何かに射影するか、そうでなければシーケンシャルにしか値が取れません。SelectDynamicは、結果の一行一行をExpandoObjectに予め射影しているので、それだけで永続化されます。

使い勝手的にはDataTableが近い。実際、例えばASP.NETでは (Container.DataItem as dynamic).PropName とすることでデータバインドも行けます。また、ExpandoObjectは何気にINotifyPropertyChangedが実装されていたりするので、存外使い勝手は良いかもですね。

DataTableと違ってデバッガに非常に優しいのも嬉しい。動的ビューで中身が簡単に確認できます。

  • Insert

Insertは指定したオブジェクトを元にInsertするというもの。

// テーブル名と対象オブジェクト(匿名型でも可)を渡すだけでInsert
DbExecutor.Insert(new SqlConnection(connStr), "Products",
    new Product { ProductName = "何か2", QuantityPerUnit = "QOQOQUN" });

Insertって書くの面倒。table名(列名)values(@列名)。クソ単純なのに……。というわけで、テーブル名とオブジェクトを指定するだけで極々シンプルなinsert into valuesに変換されます(これはExecuteNonQueryの例で出したSQL文と同じものになります)。やりたいことがシンプルなとき、シンプルに書ける。そういうのがいいなって思っていて。

  • Update

Insertと同じようなコンセプトです。

// where条件(複数の場合はand連結)とupdate対象を渡します
DbExecutor.Update(new SqlConnection(connStr), "Products",
    new { ProductName = "何か!!!" }), // update対象
    new { ProductName = "何か!", SupplierID = 100 }); // where条件
    
// 以下のようなSQLが発行されます
update Products set ProductName = @ProductName
where ProductName = @__extra__ProductName
  and SupplierID = @__extra__SupplierID

第三引数にupdateする値を、第四引数にwhereの条件を、。whereの条件は必須なのと、また、複数の場合はandで連結されます。発行されるSQLに__extra__というのが付くのはupdate対象とプロパティ名が被っても大丈夫なようにするため、なので、特に気にしなくてもいいです。比較的そのまんまなSQLに変換される、とだけ分かってもらえれば。

  • Delete

Updateと同じような(以下略)

// delete条件を渡します(複数の場合は例によってand連結)
DbExecutor.Delete(new SqlConnection(connStr), "Products",
    new { ProductName = "何か2!" });

// 以下のSQLが発行される
delete from Products where ProductName = @ProductName

ちなみに、nullだけを削除といったようなことは出来ません。いや、isnullがコマンド渡しで書けないからね…… そういうのは普通にExecuteNonQueryで書いてくださいな。そういえばでそれと、Insert, Update, Deleteは内部的にはExecuteNonQueryを実行しているので、戻り値は影響された行の個数が返ってきます。

これらは、あくまで補助的なものとして用意したので、生SQL文を完全に代替することは最初から意識していません。それが当てはまるシンプルなシチュエーションで、シンプルに書けること。それが目的です。

接続を維持しての複数クエリ/トランザクション

今までの例は全て静的メソッドの、一接続一実行の例だけでしたが、接続をつなぎっぱなしにしたりトランザクションをかけたりも出来ます。usingで囲んでnewでインスタンス化すればOK。

// 静的メソッドではなくnewすればDisposeまで接続をCloseしないモード
using (var exec = new DbExecutor(new SqlConnection(connStr)))
{
    // 今まで第一引数に渡していたコネクションが(当然)不要になる
    var count = exec.ExecuteScalar<int>("select count(*) from Products");

    // なお、ストアドプロシージャの実行は第三引数でCommandTypeを変更すればOK
    var twoyears = exec.SelectDynamic("Sales by Year",
            new { Beginning_Date = "1996-1-1", Ending_Date = "1997-12-31" },
            CommandType.StoredProcedure)
        .ToArray();
}

// 第二引数にIsolationLevelを渡すとTransactionがかかります
using (var exec = new DbExecutor(new SqlConnection(connStr), IsolationLevel.ReadCommitted))
{
    // こんな露骨でなくても、配列上に沢山オブジェクトがあって
    var products = Enumerable.Range(1, 10)
        .Select(i => new
        {
            ProductName = "Test!",
            SupplierID = i
        });
    // サクッと一気にInsertするとか、あったりなかったり
    foreach (var product in products)
    {
        exec.Insert("Products", product);
    }


    exec.TransactionComplete(); // usingを抜ける前にこれを呼び出せばCommit、呼び出さなければRollback
}

new DbExecutorの際にIsolationLevelを渡すとトランザクションがかかります。TransactionScopeのように、確定させる際は最後にTransactionCompleteを。TransactionCompleteが実行されなかった場合はRollbackされます。なお、別に普通にTransactionScopeを使っても問題ありません。

まとめ

生SQLなんて、好きじゃない!どうやったって、異物だもの。生SQL文じゃないストアドプロシージャならいいかといえば勿論そんなわけはなく、呼び出し時のパラメータと値の受け取りが……。むしろ、実態のSQL文がコードと相当離れたところに置かれ、見通しが低下するわけで、それなら逐語的文字列リテラルでC#コード中に埋めたほうがいいよ。逐語的文字列リテラルのない言語だったら、悪夢すぎて考えたくないけれど。逐語的文字列リテラルの何がいいかって、コピペでSQL Server Management Studioに移せるところなんだよね。そして逆も然りで。XMLか何かに外出しも当然イマイチで、そんなことやるぐらいなら文字列埋め込みのほうがずっといい。んー、でもS2Daoの2Way SQLというのはいいですね。パラメータの修正などもせずManagement Studioでそのまま実行可能、という。Linq to Sql/EntitiesもLinq Padを使うことでそれらしいことは出来るかな?

と、まあ、なにはともあれで、SQLをどれだけ嫌ったところで、現実問題付き合っていかなければならない。ことはなくLinq to Hogeを使いたい。けど、無理なら、それならせめて軽やかに扱いたいよね、とは皆思うはずで、皆それぞれの俺々ユーティリティは用意されていると思いますが、私も作ってみました(一年ぶりに再チャレンジで)。

特徴はIEnumerableベース(Linq to Objectsに乗っかる基盤)であることと、匿名型を多用したパラメータの受け渡し、ExpressionTreeを用いた動的デリゲート生成による高速化、dynamicによるシンプルなアクセサ。C#3, 4の機能を満遍なく使って、軽快に書けるようにしたつもりです。生SQLを扱うわりには、かなりLL的な軽さは出せてるのではないかとー。とにかく簡素なAPIになるよう気を使いました。ついでに、今回はCode Contractsも全面的に導入しています。

とりあえず、SQLCEも4.0になってDLLのみでよくなって、更にはNuGetでサクッと用意できてと(EF CodeFirstも用意できる)、C#でもデータベースがもんのすごく身近に扱えるようになりました。とてもいい事です!というわけで、生SQLのお供に是非どうぞ。Linq to SqlやLinq to Entities使っていても普通に共存出来ますので~。

まあ私は生SQLよりもCodeFirstにしたいですが!生SQLなんてどうでもいいのでLinq to Entitiesでキャッキャウフフしたいです。そんなわけでDbExecutorのテストに使ったDBは、SQLCE4+EF CodeFirstで組んであったりして。Code FirstでDB組んだのにLinq to Entitiesではなく生SQLでアクセスするとか大変モニョる。

4/30追記

ver.2.0.0.1に。ExecuteScalarの契約で事後条件を!=nullとしていたのですが、大間違いで普通にnullりるので。DbNullが返ってくるものと勘違いしていてAssumeを足してわざわざ抑制してたんですが、全くもってダメダメな対応だった……。わざわざ(静的チェッカが)警告してくれたのを、深く考えずAssumeで消すとは、愚かすぎる。そして、1日で差し替えたのにStableリリースと言い張ったことを深く反省します。なお、リリースバイナリから事後条件は削除されているので、誤った契約による問題は、静的チェッカが正しく動作しない(nullではないとマークされる)ことだけになります。その程度の軽い障害なのだから良いかといえば、勿論全然よくはなく、本当にすみませんでした。

流れるようなインターフェイス vs 生SQL

で、思い出した。基本的には私は「流れるようなインターフェイス」自体が大嫌いというのもありますが、Seasar2 - S2JDBCのような仕掛けは全く無意味だと思いますね。Linqの式木のような深い解析が出来なければ、こういうのはただのファッションで、別に書きやすくも何ともないと思っていて。それなら生SQLのほうが遥かにマシだと。だから私はDbExecutorでは前段は生SQL、後段にLinq to Objectsという形体を取っています。「生SQLは避けられないもの」という認識が大前提のうえで、それを如何にサポートするかが主眼です(まあ、なので単純に比較しても意味のないところですが)。また、C#にはLinq to Entitesもあることですし、欠けてる部分を上手く補完出来ればというのが願うところです。

XboxInfoTwit - ver.2.3.0.4

Twitterの認証周りが変わって、新規認証が出来なくなってしまってたので、それを修正しました。

Tester-DoerパターンとCode Contracts

僕と契約して安全性の高いソフトウェアを作ってよ!というだけじゃ、何か、弱い。動機付けに足りない。という、分かったような分からないようなCode Contracts。困ったところは、で、何が嬉しいの?にたいする積極的具体的な動機付けを提供しにくいということ。契約をしっかり行うことで、強固なソフトウェアが設計出来ます。うーん、理念は分かりますけど実用的に便利ー?if hoge==null throw に毛が生えた程度のものだったら、ちょっとよくわからない。

// こういうコード見るともう目も当てられなくて、画面の半分が引数チェックで埋まってるよ!
public void Hoge(string arg1, string arg2, string arg3)
{
    if (arg1 == null)
    {
        throw new ArgumentNullException("arg1");
    }
    if (arg1.Length == 0)
    {
        throw new ArgumentException("arg1");
    }
    if (arg2 == null)
    {
        throw new ArgumentNullException("arg2");
    }
    if (arg2.Length == 0)
    {
        throw new ArgumentException("arg2");
    }
    if (arg3 == null)
    {
        throw new ArgumentNullException("arg3");
    }
    if (arg3.Length == 0)
    {
        throw new ArgumentException("arg3");
    }
    
    // やっとメソッドの本体...
}

うん、これは、イヤ。ifは必ず{}をつけなければ、とやると行数が嵩んで最悪の視認性に。個人的には、明らかに一行な処理はifの真横に書いてもいいと思う。

// これぐらいなら許す(えらそう)
public void Hoge(string arg1, string arg2, string arg3)
{
    if (string.IsNullOrEmpty(arg1)) throw new ArgumentException("arg1");
    if (string.IsNullOrEmpty(arg2)) throw new ArgumentException("arg2");
    if (string.IsNullOrEmpty(arg3)) throw new ArgumentException("arg3");

    // ↑もしくはGuard.NotNull(arg1, "arg1"); とか用意するなど、ね。
}

そんなわけかで、この手のnullチェックが好きでなくて、必要性だって、どうせ次の行のその引数使うところで死ぬんだからどうでもよくね?と思う場合があまりにも多いともにょもにょもにょ。書くけど書かないけど。

その延長線上でContractsも面倒くさいしなー、と思っていた時もありました。しかしCode Contractsは、あらゆる方向から契約を積極的に行うための動機付けを提供してくれています。Premiumにしか提供されていない静的チェックが最も強力なのは確かですが、Standardのユーザーのためにも、ドキュメント生成、IntelliSense表示サポート、Pex自動テスト生成サポート、引数名を文字列で書かなくていい。などなど。

そこまであの手この手で、契約するといいよ、と迫ってこられれば納得です。理屈上素晴らしいから、というだけじゃなくて、何だかんだで面倒くさいものを、現実的にこんなにメリットがあるから契約しようよ!という。そういう姿勢がいいよね、普及させるために全方位から攻めるというの。それだけ並べられれば、そりゃ書くってものですよ?

特にIntelliSense厨の私は、IntelliSenseへの契約表示に感動しまして。Enumerable.Rangeで条件が表示されてるよ、きゃー!って。そして、BCLが契約を表示してくれるなら、自前のクラス群も契約表示させてあげたい。と、いうのが一番のCode Contractsやろう!という動機付けになりましたね。頻繁にクラッシュするんですが、その辺は多めに見てあげます。

Tester-DoerパターンとCode Contracts

Code Contracts自体は第54回CLR/H勉強会発表資料を公開します。 - Bug Catharsisの「オブジェクト指向と契約による設計」と「Code Contracts入門」という資料が素晴らしいので、今すぐそちらを見たほうがいいです!

というわけでCode Contracts自体には全く触れないで、例でも。

// Addのないstring, string辞書(これはひどい)
public class StringDictionary
{
    Dictionary<string, string> dict = new Dictionary<string, string>();

    public bool ContainsKey(string key)
    {
        return dict.ContainsKey(key);
    }

    public string Get(string key)
    {
        return dict[key];
    }
}

static void Main(string[] args)
{
    var dict = new StringDictionary();

    // 存在しないキーをGetすると例外
    dict.Get("hogehoge");

    // チェックしてから取得する(Tester-Doerパターン)
    if (dict.ContainsKey("hogehoge"))
    {
        dict.Get("hogehoge");
    }
}

取得時にダメな可能性があるものは、先にチェックしてから取りに行く。といったことは、.NETのクラスライブラリ設計に書いてあるので読もう~。とてもお薦め本。

問題は、キーの存在チェックをすることがほぼ必須なのに、それを強制出来ないんですね。あくまで任意でしかなく、別にチェックしなくてもコンパイラ通るし、そうして書かないでいるとうっかりな例外発生の可能性を常に抱えてしまう。こういう問題は例外自体にも言えますが。ほぅ、では検査例外が必要か…… いえ、あれはいりません。

まあともかくで、ここでCode Contractsを使うとどうなるか、というと……

public class StringDictionary
{
    Dictionary<string, string> dict = new Dictionary<string, string>();

    [Pure] // Pureじゃないと怒られるのでPureってことにしておこう(善意の申告制です)
    public bool ContainsKey(string key)
    {
        return dict.ContainsKey(key);
    }

    public string Get(string key)
    {
        Contract.Requires(ContainsKey(key)); // 事前条件 ContainsKeyがtrueでなければダメ

        return dict[key];
    }
}

static void Main(string[] args)
{
    var dict = new StringDictionary();

    // ContainsKeyの前にGetしようとすると...
    dict.Get("hogehoge");
}

静的チェッカーが警告を出してくれます。いいねいいね。そんなわけで、Code Contractsを使うと、比較的安全にTester-Doerパターンが適用できるのでした。こういう、コードだけでは表現できない約束事を表現でき、実行時ではなくコンパイル時に検出出来るようになる、っていうのは、魅力的な話なのではと思います。

まとめ

Code Contractsは一部で無理矢理感が否めません。そもそもバイナリリライター必須なうえに、文法的にもContract.Requiresぐらいならまあいいとしても、Ensures(Contracts.Result)やInvariantやContractClassForはC#的に不自然さを残す介入の仕方で、些か残念と言わざるをえない。

不自然さ漂う記述方法がC#に統合される(それSpec#)日は来るのだろうか(絶対来ないよね)。Spec#は軽く仕様とTutorialを眺めた感じだと、やはり言語統合されてると、洗練されてるし、書きやすさも段違いになるよねえ、などと思いました。全ては必要ないけれど、一部はC#に入って欲しい、のですが文法と衝突しなくても、既存のコードとルールが衝突してしまったりするので難しいかなあ。

とはいえ、Code Contracts全体のエコシステムがもたらすメリットも多大だし、mscorlibすらContractsが書き足されている(.NET4から)ぐらいなので、今のうちにそれに従って流行りものに乗っかるのもいいと思います。流行ってるか謎ですが。単純なnullチェックぐらいならサクッと書けますが、少し凝った契約をしようとすると途端にワケワカランし正道がサッパリ。という敷居の高さはありますが……。

実際ヨクワカラナイデス。少しよーし、張り切って書いちゃうぞー、とやると、それダメそれダメ、とリライターに言われてしまったりでnullチェックに毛の生えた程度しか使いこなせない昨今です。それだけでも有益といえば有益なんですが、あちこちでrequires not null, ensures not nullを書いていると、もうデフォルトを非nullにしてくれよ!と叫ばずにはいられない。何ともいえない不毛感がちょっと、かなり、嫌。

あと、静的チェッカが上手く機能するように書くには静的チェッカが必要なのも。当たり前?うーん、静的チェッカなしで、ただ普通にContractsを書いているだけじゃあダメなのかな?契約自体は成立していてリライターは通るけど静的チェッカ使うと警告だらけ。みたいな形になりがちで。Standardで書いてPremiumでチェックしたら涙目の落差が激しすぎて、じゃあ結局は静的チェッカ必須なの?でもそれPremium以上じゃん、というのが残念で。そうなるとStandardにも欲しいねえ、静的チェッカー。

でも、ちょっと気の利いたGuard句として、事前条件だけで画面半分が埋まるような事態が緩和されるなら、それはとっても嬉しいなって。まずは、その程度から始めよう。順を追ってステップアップすればいいのだから。

Expression Treeのこね方・入門編 - 動的にデリゲートを生成してリフレクションを高速化

Expression Treeは、IQueryableの中心、Code as Dataなわけですが、それ以外にも用途は色々あります。ただたんに名前を取り出すだけ(考えてみると贅沢な使い方よね)とか、デリゲートを生成したりとか。varはLinqのために導入されたものだからそれ以外に無闇に使うのは良くない(キリッ とか言う人は、式木も同じ考えなんですかね、匿名型へも同じ態度で?導入された、そして発展させたのはLinqだとしても、別にそれ以外に使ってもいいんだよって。縛られた考えイクナイ。

というわけで、今更に、初歩からの式木再入門。特に.NET 4から大幅に拡張されて式だけじゃなく文までいけるようになって、何でも表現出来るようになりました。式木の用途は多岐に渡るわけですが、今回はリフレクションの高速化をお題にしたいと思います。プロパティ名の文字列からPropertyInfoを取ってGetValueといったように、動的に値のGet/Setをするわけですが、それを動的コード生成で高速化しよう!

方針としては、プロパティアクセスのデリゲートを生成します。GetだったらFunc<object, object>を作って、引数が対象インスタンス、戻り値が取得結果の値、といった具合です。まんまPropertyInfoのGetValueがデリゲートになったもの、といった具合。

では、実際に書きながら見ていきます。というわけで、私の書き方などりを順を追って。まず、何をやりたいかを明確にするため、実際のコードで、具体的なラムダ式を書いてコンパイル通します。

// 適当なクラス
class MyClass
{
    public int MyProperty { get; set; }
}

static void Main(string[] args)
{
    // これで書くと(.NET 4以降の)代入やループはサポートされてないので、Funcでも全然いいです
    // ただ、デバッガで生成された式の結果が見えるので、Expressionでコンパイル通せたほうが楽かな
    Expression<Func<object, object>> expr =
        target => ((MyClass)target).MyProperty;
}

コンパイル通るということは、それで書けるということ。机上で、頭の中だけで考えてもいいことありません。ささっとコンパイラ使いませう。そして一旦デバッガでexprを覗いてみますと

// ToString()
// target => Convert(Convert(target).MyProperty)

// DebugView
.Lambda #Lambda1<System.Func`2[System.Object,System.Object]>(System.Object $target) {
    (System.Object)((Program+MyClass)$target).MyProperty
}

Expressionで宣言して書くというのは、コンパイラがコンパイル時に式木を生成するということです。見た目はFuncに毛が生えた程度なのに、コンパイル結果は大違い。なんて恐ろしい!そして、なんて素晴らしい!ともあれ、結果から逆算してくのが手っ取り早い。大枠は機械生成に任せてしまって、微調整だけを手動でやればいいわけで。無から作るのは大変ですが、枠組みが出来ているなら簡単だもの。このToStringとDebugViewは大変便利です。なお、リフレクタで生成結果を見るという夢のない方法もあります。

上記結果から、具体的な成分に置き換えた、何を書くのかの式をイメージ。

// (object target) => (object)((T)target).PropertyName

もう、あとは機械的に置き換えていくだけ!というわけで、具体的にこねこねしていきますが、まずパラメータとラムダ本体を用意します。この二つは、最終的にデリゲートの生成を目指した式木の作成では定型句みたいなものなので何も考えず用意。

// まず、引数のパラメータとLambda本体を書く
var target = Expression.Parameter(typeof(object), "target");

var lambda = Expression.Lambda<Func<object, object>>(
    /* body */
    , target);

基本的に、埋めやすいところから埋めていくのがいいのではないかなー。そして、Expressionは最後の引数が一番埋めやすいので、外から内に向かって書いていくことになります。最初のLambdaは、引数パラメータを最初に置いてしまって、bodyは後回しにする。というわけで、これで左辺は終了しました。次は右辺。外周から構築されるので、まずobjectへのキャスト。これはExpression.Convertです。

var lambda = Expression.Lambda<Func<object, object>>(
    Expression.Convert(
        /* body */
        , typeof(object))
    , target);

当然ですが、ちゃんとインデントつけたほうがいいです。カンマ前置は気持ち悪いですが、こうして後ろから埋めていく時は、こっちのほうが書きやすいかなー。気持ち悪ければ最後にまとめて直せばいいのではないかと。

次はTへのキャスト、ではなくプロパティ呼び出し。実行の順番はTにキャスト→プロパティ呼び出し→objectにキャストですからね。プロパティ呼び出しはExpression.Property。ですが、フィールドも似たようなものだし、幸いExpressionには両者を区別しないPropertyOrFieldがあるので、そちらを使いましょう。名前はstringで渡しますが、とりあえず"PropertyName"で。

var lambda = Expression.Lambda<Func<object, object>>(
    Expression.Convert(
        Expression.PropertyOrField(
            /* body */
            , "PropertyName")
        , typeof(object))
    , target);

最後は((T)target)。(T)は後で置き換えるとして、とりあえずMyClassにしておきますか。targetは、最初に作った右辺のパラメータです。

var target = Expression.Parameter(typeof(object), "target");

var lambda = Expression.Lambda<Func<object, object>>(
    Expression.Convert(
        Expression.PropertyOrField(
            Expression.Convert(
                target
                , typeof(MyClass))
            , "PropertyName")
        , typeof(object))
    , target);

埋まった!埋まったらとりあえずまずコンパイル。するとPropertyNameはMyClassにないよ、と例外出て終了。ふむふむ。ところで、ここでチェック入るんですね、へー。それでは、別関数に分けることを意識して、(ようやく)変数用意しますか。

// あとで関数の引数にするとして
var type = typeof(MyClass);
var propertyName = "MyProperty";

var target = Expression.Parameter(typeof(object), "target");

var lambda = Expression.Lambda<Func<object, object>>(
    Expression.Convert(
        Expression.PropertyOrField(
            Expression.Convert(
                target
                , type)
            , propertyName)
        , typeof(object))
    , target);

コンパイル通ったー。そしたら、とりあえずデバッガでlambda変数を観察。ToString結果とDebugViewプロパティを見るといいでしょう。

// lambda.ToString()
target => Convert(Convert(target).MyProperty)

// lambda.DebugView
.Lambda #Lambda1<System.Func`2[System.Object,System.Object]>(System.Object $target) {
    (System.Object)((Program+MyClass)$target).MyProperty
}

問題なさそうですね!この二つは作るときに非常に便利なので、大きめのを書くときは断片を書いてこれでチェック、みたいにするといいかも。では、最後にデリゲート生成(Compile)を。

// デリゲート生成!
var func = lambda.Compile();

// てすと
var test = new MyClass { MyProperty = 200 };
var result = func(test);
Console.WriteLine(result);

というわけでした。DynamicMethodでILもにゃもにゃ(敷居高すぎ!)とか、Delegate.CreateDelegateだのでもにゃもにゃ(面倒くさい!)に比べると、随分素直に書けて素敵。.NET 4.0からはブロックやループなど、式だけではなく全ての表現が可能になったので、動的コード生成が身近になりました。

Setのほうも同様な感じに書けます。

// (object target, object value) => ((T)target).memberName = (U)value
static Action<object, object> CreateSetDelegate(Type type, string memberName)
{
    var target = Expression.Parameter(typeof(object), "target");
    var value = Expression.Parameter(typeof(object), "value");

    var left =
        Expression.PropertyOrField(
            Expression.Convert(target, type), memberName);

    var right = Expression.Convert(value, left.Type);

    var lambda = Expression.Lambda<Action<object, object>>(
        Expression.Assign(left, right),
        target, value);

    return lambda.Compile();
}

// Test
static void Main(string[] args)
{
    var target = new MyClass { MyProperty = 200 };
    var accessor = CreateSetDelegate(typeof(MyClass), "MyProperty");

    accessor(target, 1000); // set
    Console.WriteLine(target.MyProperty); // 1000
}

Expression.Assignが代入なのと、objectで渡されるvalueは、プロパティに代入する際にプロパティの型へキャストする必要があるので、left.Typeで取り出しています。これ、Lambdaの中に一気に書いてしまうと値が取れないので、外で書く必要があるのが少々面倒かしらん。とりあえず、コメントで生成後の式を書いておいてあげると見る人に(少しだけ)優しい。

今回のSet/Getは微妙に汎用的なものにするため全てobjectで扱っていますが、ジェネリクスにすれば、余計なExpression.Convertがなくてスッキリ記述+パフォーマンスも向上、が狙えそうですねん。

何で突然?

思うところあって、じゃなくて、WP7にSQLCE搭載の報を受けて、以前書いたデータベース用ユーティリティを書き直そうと思いまして。そして、コマンドパラメータの受け渡しには匿名型を使おうかな、と。そうすると、書くのがとても簡単になるんですね。凄く軽快で。これは良い。のですけど、実行の度にPropertyInfoを取ってきてNameとGetValueでの値取り出しはどうかと思ったわけです。そりゃねーよ、と。そこで、じゃあ、キャッシュしよう。キャッシュするならPropertyInfoをキャッシュしたってそんな速くはない、やるならデリゲート生成までやろう。と、紆余曲折あってそうなりました。

パラメータだけではなくて、簡易マッパー(selectの各カラムの名前とプロパティ名からインスタンス生成)も用意しているのですが、それもデリゲートのキャッシュで高速化効いてくるかなー、と。

で、速いのかというと、うーん、生成のコストが結構高いので、平均取ると、PropertyInfoのキャッシュと比べると、数千回実行しないとコスト回収出来ないかも。PropertyInfoのGetValueも遅い遅いというほどにそんな遅くないのかなあ、いや、デリゲートと比べると十数倍ぐらいは違うんですが、しかし。マッパー的に使って、一回の実行に100行取ってくる、とかだったら余裕ですぐ回収出来ますが、コマンド程度だとどうだろうなー。まあ、ASP.NET MVCなんかはTypeDescriptor(正直遅い)経由でやってるみたいだし、それと比べれば悪くないかもはしれない。でもWP7を見ると、アプリケーションのキャッシュ生存期間を考えると、ペイ出来そうな気がしない。

とはいえ、初回に少し重くてあとは高速、のほうがユーザーエクスペリエンス的にはいいかな、と思うので(あと、どちらにせよたかが知れてる!)、式木デリゲートキャッシュは採用の方向で。スッキリしてて、C#らしい美しさなところも好き。で、まあ一応、速度を気にしてのことなので、ベンチマークを取ったりするわけですが、生成時間が気になる……。エクストリームにハイパフォーマンスなシリアライザを作る!とかってわけじゃないので、あんまキチキチに気にしてもしょうがないのですが、でもちょっと気になる。Boxingが~、とかも少し、でもそれは放置として。

リフレクションは遅いから情報をキャッシュするとかのお話 - Usa*Usa日記 [雑記] 動的コード生成のパフォーマンス (C# によるプログラミング入門) 動的プロキシなViewModelの実装とパフォーマンスの比較(MVVMパターン) - the sea of fertility 効率の良い実行時バインディングとインターフェイス指向プログラミングでの boxing の回避テクニック - NyaRuRuの日記 パフォーマンスのための Delegate, LCG, LINQ, DLR (を後で書く) - NyaRuRuの日記 インライン・メソッド・キャッシュによる動的ディスパッチ高速化 - @IT ByRef parameter and C# - 猫とC#について書くmatarilloの日記 c# - How does protobuf-net achieve respectable performance? - Stack Overflow HyperDescriptor: Accelerated dynamic property access - CodeProject Making reflection fly and exploring delegates - Jon Skeet: Coding Blog patterns & practices – Enterprise Library(Data) MetaAccessor クラス (System.Data.Linq.Mapping) TypeDescriptor クラス (System.ComponentModel) AutoMapper csharp/msgpack at master from kazuki/msgpack - GitHub cli/src/MsgPack at master from yfakariya/msgpack - GitHub

ネタ元。先人が百億光年前に辿ってきた話だ、的な何か。コードは、シリアライザやマッパーはこの辺の仕組み載せてるよね、という当たりをつけて、ソースコードをPropertyInfoやDictionaryで検索してヒットした周辺を眺めるなど。で、まあ、分かったような分からないような。キャッシュの仕組みと含めて、上手くまとまったらDynamicJsonにも載せようと思っているんですが。一週間ぐらい延々と弄ってるんですが、どうも固まらなくて。この辺、コード書きの遅さに定評のある私です(キリッ。

ちなみにWP7には今のところExpression.Compileはないんですけどね!(Betaの頃はあったけど削られたよう)。SQLCE搭載でLinq to Hogeも搭載するはずなので、それと一緒に復活するはずと信じています。あとSL4相当じゃないとExpression.AssignやUnboxが使えなくてどちらにせよ困るので、MangoではSL4相当にグレードアップしてくれないと。もし一切変わらなかったら、IL生成はもとから出来ないし将来も搭載されないと思うので、適当に何かでお茶濁しますか。

Linq と Windows Phone 7(Mangoアップデート)

今冬に予定されている大型アップデート(Mango)に向けて、MIX2011で大量に情報出てきました。色々ありましたが、その中でも目を引いたのがデータベース対応とQueryable対応。データベースは恐らくSQL Server Compact 4.0相当で、これはいいものだ。ただ、生SQL文かあ、という思いもあり。他のやり方ないのかなあ。オブジェクトDBとか?などと夢見てしまうけれど、高機能なエンジン(SQLCE4)がある以上は、それをそのまま使ったほうがいいのは自明で。

インピーダンスミスマッチを解消する、そのためのLinqでしょ!と、ああ、そうだね。でもLinq to Sqlはないし、Linq to Entitiesが乗っかるわけもないし、策はなく普通に生SQLの気もするなあ。どうでしょうね。どうなるのでしょうね。で、Queryable対応も発表された、というかデモられていました。

これでDB+Linqがあることが保証されたから安泰。何のQueryProviderと見るべきかしら。この辺、不透明なので、情報入り次第しっかり追っかけます。

Queryableの難点は、見た目はスッキリしてますが、コンパイル後の結果は式木のお化けになる+実行時は式木のVisitというわけで、軽い処理とは言い難いところなのですが、軽いとか重いとか気にしないし!じゃあなくて、MangoではGC改善など性能向上も入るようなので、十分なパフォーマンスは確保できそうです。あと、ユーザーエクスペリエンスを損なうボトルネックは結局そこじゃあないんだよ、的なこともありそうだし。

例えば現行のWP7のListBoxは致命的に重くて、純正アプリは軽いのにユーザー作成アプリではクソ重く、純正だけネイティブでチートかよゴルァ、という勢いだったんですが(Mangoで改善されるそうです!)、これの要因の一つは画像の読み込み周りがアレだったことにあるようで……。

CocktailFlowという素敵な見た目のアプリがあるのですが、これはその辺の問題に対処するためか、事前にLoadingを取って、完全に読み込み終わってからしか表示しないようになってます。でも、それはそれでネットワーク読みに行ってるわけでもないのにLoadingが長くて、微妙だなあ、と。

MIX11でのRx

二つセッションがありました。一つはLinq in Actionの著者(最初期に出たものですが、良い内容でしたね)によるWP7でのRx活用例。

マイクのボリュームが不安定で聴きにくいですー。話はPull(Enumerable)とPush(Observable)の比較から入ってますね。MoveNextして、MoveNextして、MoveNextして、ええ、ああ、メソッド探訪第7回:IEnumerable vs IObservableの辺りで書きましたね~。それのEnumerbaleサイドのリライト版であるLINQの仕組みと遅延評価の基礎知識の続きとして「Rxの仕組み」を書きたいのですが書くと思ってもう3ヶ月も経ってる、うぐぐ……。

話がそれた。んで、話の序盤は結構退屈です。IEnumerator vs IObserverとかつまらないです、って、あ、私もやってたっけ……。話の流れを上手くつながないと何か唐突なのね。さて、デモはサイコロ転がしを完成させていくというもの。どんどんコードがメソッドチェーンのお化けになっていく様はどこかで見たことある(笑)。最初は、重たい処理を、ObserveOn(Scheduler.ThreadPool)とするだけで実行スレッドを切り替えて、CPUバウンドの処理を簡単に同期→非同期に変換してUIをブロックしないというデモ。ちなみにObserveOn(Scheduler.ThreadPool)じゃなくて、これはToObservableの時点でScheduler渡したほうがいいんじゃあないのかなあ。まあ、大して違いはないといえばないですがー。

次は加速センサーをRxに変換して、TimestampをつけてShakeされたことを検出するというもの。生のセンサーイベントをRxで事前に加工して扱いやすくする、という手ですね。私もUtakotohaの再生イベントでそれやったよ!(いちいち対抗心燃やして宣伝しなくてよろし)。ObservableだとMockに置き換えやすいんだよ、という話もね。気づいたらメソッドチェーンのお化けになっているのも。Linq使いの末路はみんなこんなのになってしまうという証明が!

セッションはもう一つ。RxチームのBart De SmetによるRxJSのセッション。MIX2011はIE10と合わせてHTML5推しもありましたしね。

最初の20分は、ObservableとObserverの購読概念などについて簡単な説明。あとRange,FromArray,Timerといった生成子。Pullとの比較がない、つまり"Linq"とは全く言わないのがJavaScript向けですね。喩えもHTML5のGeolocation APIが、などなど新鮮。そして、だからこそ分かりやすいかもしれません。その後はいきなりGeolocation APIをラップする自作Observableを作ろうが始まって難易度が、まあLevel300だものね。実用的な話ではあるし、Observableを作るということは仕組みを理解するという話でもあるので、こういうのも良い流れ。ほか、KeyUpを拾ってネットワークを問い合せてのリアルタイム検索(event+asynchronousの合成例)など。これはハンズオン資料でもお馴染みの例ですが、順に追ってデモしてもらえるとThrottleの意味は凄く分かりやすいですね。Switchも強力だけど分かりづらさを持つので、こうして丁寧に解説してもらえると、いいね。ともかく、概念としてC#もJavaScriptも超えたところにあるので、考え方、コード例はC#/WP7でも使えます。良いセッションだと思いますので見るのお薦め。

そういえばで、Async CTPが更新されていて、一部変更があったので、RxとAsyncとのブリッジライブラリ(Rx-AsyncLinq)が動かなくなったと思われるので、それに合わせて近いうちにRxもアップデートありそうな気がします。RxJSもここずっと更新とは遠かったのですが、こうしてセッションもあったことだし、大型アップデートはあってもおかしくないかな。

Async CTPはufcppさんの記事Async CTP Refreshに詳しく書かれていますが、ライセンス形態がご自由にお使いください(※但し自己責任)へと変更、日本語版でも入るようになった、WP7対応、といった具合に、WP7開発でも今すぐ投下しても大丈夫だ問題ないになったのは大きい。

他言語からWP7開発のために来たので、C#の経験があまりなくてLinqがイマイチ分からない。でも非同期ダルい。という人には、Rxよりも、Asyncのほうがずっと扱いやすく応えてくれるので、なし崩し的に投入してしまっていい気がしますねー。勿論、ある程度は大きな変更に対応していく気は持ってないとダメですが。

ある程度Linqが分かる人なら(別にそんな大仰なスキルを要求するわけじゃなく、SelectしてWhereして、Linq便利だな~、ぐらいでいいです!)Rxを学ぶのもお薦め。基本的にはLinqに沿っているので、学習曲線はそんなにキツくないです。特に、非同期をラップしてWhereしてSelectしてSubscribe、ぐらいならすぐ。他のは、徐々に覚えればいいだけで。

まとめ

WP7はRx標準搭載で、ただでさえLinq濃度が高かったというのに、Queryable搭載でLinq天国に!もはやWP7が好きなのかLinqが好きなのかよくわかりませんが(多分、後者です)、ともかく最高のプラットフォームなのは間違いない。

ところでDay1ではnugetが割とフィーチャーされていたのですが、その背景、よくみると……

右のほうにlinq.jsが!すんごく嬉しい。

Utakotoha - Windows Phone 7用の日本語歌詞表示アプリケーション

マーケットプレイスに通り、公開されました。フリーです(下で述べますがソースも公開しています)。再生中の音楽のアーティスト・タイトルを元に自動で検索して、歌詞を表示する、というものです。海外製の同種アプリとの違いは、対象が日本の曲ということになります。下記バナー、もしくはマーケットプレイス検索"utakotoha"でどうぞ。アプリケーション名は例によってヒネりなしで「歌詞」からそのままとりました。うたのことば。Utakata TextPadと名前が似ていますが偶然の一致です(ほんと)

スクリーンショットでは格好つけてズームインして隠蔽していますが、スクリーンショット用詐欺なだけで、実際はこんな感じです。

ようは、単純にWebBrowserにgoo歌詞を出しているだけです。ダブルタップでエリアに沿って幅一杯の拡大してくれるので、誤魔化し的にはまぁまぁ。WebBrowserを経由する理由は、APIが提供されているわけでもないので、権利関係考えるとこうでないとマズいかな、といったところで。goo歌詞を選んだ理由も直リンが許可されていたからです。

あと、WP7はテーマに黒背景のDarkと白背景のLightがあるわけですが、goo 音楽の背景は強制白で、どうもミスマッチなわけですね。アプリ自体を完全に白背景にしてしまうのもいいかな、とは思ったんですが、ブラウザのCSSを書き換えて黒背景にするという手を(ネタとして)取ってみました。オプションでOFFに出来るというか、デフォルトはOFFです。ズームすれば違和感はないんですが、画面いっぱいに広がってるものでは、微妙度極まりない。

ほか、Twitterに再生中楽曲を投稿する機能があります。

ソースコード

CodePlex上で公開しています。単機能アプリですので、コード規模は小さめです。あまりしっかりとはしてませんが、ユニットテストなども書いてあります。

WP7のReactive Extensions実践例サンプル、のつもりで書いたので、Rxを全面的に使っています。むしろRx縛りと言ってもいいぐらいにRxのみでやるのを無駄に貫いています。意味がなくてただ複雑化しただけの箇所多数。UIと絡めて使うのがイマイチ分からず振り回されてますねー。とはいえ、バッチリはまった部分も勿論あり。というわけで、Windows Phone 7においてReactive Extensionsがどのような場所で使えるのか、というのをコードとともに解説していきます。

コードはWindows Phone 7向けですが、通常のSilverlightでもWPFでも適用できる話なので、WP7関係ないからー、と言わず、Rxに興味ありましたら、眺めてみてください。

Linq to Event

Rxの特徴の一つはイベントのLinq変換です。Linq化して何が嬉しいかというと、柔軟なフィルタリングが可能になることです。WP7では、センサーからのデータ処理やタッチパネルなど、様々な箇所で威力を発揮すると思われます。UtakotohaではMediaPlayerの再生情報の変化に対してRx化とフィルタリングを施しました。

// Model/MediaPlayerStatus.cs
public class MediaPlayerStatus
{
    public MediaState MediaState { get; set; }
    public ActiveSong ActiveSong { get; set; }

    public static MediaPlayerStatus FromCurrent()
    {
        return new MediaPlayerStatus
        {
            MediaState = MediaPlayer.State,
            ActiveSong = MediaPlayer.Queue.ActiveSong
        };
    }

    public static IObservable<MediaPlayerStatus> ActiveSongChanged()
    {
        return Observable.FromEvent<EventArgs>(
                h => MediaPlayer.ActiveSongChanged += h, h => MediaPlayer.ActiveSongChanged -= h)
            .Select(_ => MediaPlayerStatus.FromCurrent());
    }

    public static IObservable<MediaPlayerStatus> MediaStateChanged()
    {
        return Observable.FromEvent<EventArgs>(
                h => MediaPlayer.MediaStateChanged += h, h => MediaPlayer.MediaStateChanged -= h)
            .Select(_ => MediaPlayerStatus.FromCurrent());
    }

    // (省略)すぐ下に...
}

Rx化は、ただFromEventをかますだけです。また、その際に、IEventではなく、本当に使う情報にだけ絞ったもの(この場合はMediaStateとActiveSong)をSelectで変換しておくと色々とコードが書きやすくなるのでお薦めです。

さて、「柔軟なフィルタリング」とは何か。ただデータを間引くだけなら、イベントの先頭でif(cond) return;を書けばいいだけです。RxではLinq化により、(自分自身を含めた)イベント同士の合成と、時間軸を絡めた処理が可能になります。これにより、従来一手間だった処理がたった一行で、連続した一塊のシーケンスとして処理することが可能になりました。

Utakotohaでも、生のイベントをそのまま扱わず、ある程度間引いて加工したものを渡しています。

/// <summary>raise when ActiveSongChanged and MediaState is Playing</summary>
public static IObservable<Song> PlayingSongChanged(int waitSeconds = 2, IScheduler scheduler = null)
{
    return ActiveSongChanged()
        .Throttle(TimeSpan.FromSeconds(waitSeconds), scheduler ?? Scheduler.ThreadPool) // wait for seeking
        .Where(s => s.MediaState == MediaState.Playing)
        .Select(s => new Song(s.ActiveSong.Artist.Name, s.ActiveSong.Name));
}

「再生中かつx秒間(デフォルトは2秒)新しいイベントが発生しなかった最新のものだけを流す」というものです。どういう意味かというと、連続で楽曲をスキップした時。Utakotohaでは再生曲の変更に合わせて、自動で歌詞検索をしますが、連続スキップにたいしても全て裏で検索に走っていたらネットワークの無駄です。なので、2秒間だけ間隔を置いて連続スキップされていない、と判断した曲のみを歌詞検索するようにしています。

こういう処理は、地味だけど必ず入れなければならない、けれど面倒くさい。でも、Rxを使えばなんてことはなく、Throttleで一撃です。Timer動かしたりDateTimeを比較したりなんて、もうしなくていいんだよって。

/// <summary>raise when MediaState Pause/Stopped -> Playing</summary>
public static IObservable<Song> PlayingSongActive()
{
    return MediaStateChanged()
        .Zip(MediaStateChanged().Skip(1), (prev, curr) => new { prev, curr })
        .Where(a => (a.prev.MediaState == MediaState.Paused || a.prev.MediaState == MediaState.Stopped)
            && a.curr.MediaState == MediaState.Playing)
        .Select(s => new Song(s.curr.ActiveSong.Artist.Name, s.curr.ActiveSong.Name));
}

こちらは、状態が停止->再生になったことを検知するというもの。停止->再生でも自動検索を走らせたいので。

この source.Zip(source.Skip(1), /* merge */) は、一見奇妙に見えるかもしれませんが、ある種のイディオムです。一つ先(Skip(1))の値と合流するということは、Skip(1)時の値を基準にすると、現在値と一つ前の値で合流させることができる、ということになります。それにより、一つ前の状態を参照して停止->再生を検知しています。

過去の値を参照するには、他に、Scan(Aggregateの列挙版、そう考えると現在値と一つ前の値が使えることのイメージつくでしょうか?)やBufferWithCount(Listでバッファを持つ、第二引数でずらす範囲を指定可能)など、幾つかやり方がありますが、このZip(Skip(1))が最も扱いやすいところ。ただし、通常のものとSkipしたものとで、二つ分Subscribeされるということは留意したほうがいいかもしれません。そのことが問題になるケースもあるので、キャッシュを使う(Pulish(xs=>xs.Zip(xs.Skip(1)))など回避策を頭に入れておくと良いケースもあります。

Linq to Asynchronous

Rxのもう一つの大きな特徴は非同期のLinq変換です。そうすることにより、コールバックの連鎖で扱いにくかった非同期が、一本の流れに統一されます。

Utakotohaでは、歌詞の検索部分が代表的です。歌詞検索の背景ですが、goo歌詞のものを表示しているのだからgoo歌詞の検索を呼んでやるかなあ、と思ったのですが、それは色々マズいので、Bing Apiのサイト内検索を経由して、表示しました。Bing Apiについては若干苦労話もあるので、いつかまた。

// Model/Bing/BingRequest.cs
public IObservable<SearchWebResult> Search(params SearchWord[] keywords)
{
    var req = WebRequest.Create(BuildUrl(keywords));

    return Observable.Defer(() => req.GetResponseAsObservable())
        .Select(res =>
        {
            var serializer = new DataContractJsonSerializer(typeof(SearchWebStructure));
            using (var stream = res.GetResponseStream())
            {
                return (SearchWebStructure)serializer.ReadObject(stream);
            }
        })
        .SelectMany(x => (x.SearchResponse.Web.Results != null)
            ? x.SearchResponse.Web.Results
            : Enumerable.Empty<SearchWebResult>());
}

割とあっさり。Bing APIならびにJSONに関しては、以前Windows Phone 7でJSONを扱う方法について(+ Bing APIの使い方)として書きました。ほとんどそのままです。SearchResponse.Web.Resultsは、配列なので、SelectManyで分解してやります(nullの場合は空シーケンスを流す)。すると、後続に繋げるのが非常にやりやすくなります。実際に

// Model/Song.cs
public IObservable<SearchWebResult> SearchLyric()
{
    return new BingRequest()
        .Search(MakeWord(Artist), MakeWord(Title), LyricSite, Location, Language)
        .Where(sr => sr.Url.EndsWith("index.html"))
        .Do(Clean);
}

といったように、Searchから更に続いて、若干のフィルタリングが入っています。これを使う場面では、勿論、更にチェーンが続きます。といったように、Rxは一つの流れを構築するわけですが、それらを徹底的に分解・分割して適切な場所への配置・組み合わせが可能になっています。もし、通常の非同期処理のようなコールバックの連鎖だったら、組み合わせは大変でしょう(だから、その場だけで処理したくなって、ネストが嵩んでしまう)

Orchestrate and Coordinate

Rx全体の特徴として、また、他の非同期を扱うライブラリと最も異なる、しかし重要な点として、中に流れるデータを区別しません。非同期もイベントもタイマーもオブジェクトシーケンスも、全て同列に扱います。それはどういうことかというと、データの種別を超えて合成処理が可能になるということです。つまり、Rxは、あらゆるデータソースを統合する基盤といえます。上のAsynchronousの例でも、非同期のWebResponseが、SelectMany以降はオブジェクトシーケンスに摩り替わっていました。

Utakotohaでは、歌詞の表示部分で色々なデータを混ぜあわせる処理を行っています。

// View/MainPage.xaml.cs
LyricBrowser.NavigatedAsObservable()
     .Where(ev => ev.EventArgs.Uri.AbsoluteUri.Contains(GooLyricUri))
     .SelectMany(ev =>
     {
         // polling when can get attribute
         return Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(3))
             .ObserveOnDispatcher()
             .Select(_ => (ev.Sender as WebBrowser).SaveToString())
             .Select(s => Regex.Match(s, @"s.setAttribute\('src', '(.+?)'"))
             .Where(m => m.Success)
             .Take(1);
     })
     .Select(m => WebRequest.Create(GooUri + m.Groups[1].Value).DownloadStringAsync())
     .Switch()
     .Select(s => Regex.Replace(s.Trim(), @"^draw\(|\);$", ""))
     .Where(s => !string.IsNullOrEmpty(s))
     .ObserveOnDispatcher()
     .Subscribe(jsonArray =>
     {
         // insert json array to html
         LyricBrowser.InvokeScript("eval", @"
            var array = " + jsonArray + @";
            var sb = [];
            for(var i = 0; i < array.length; i++) sb.push(array[i]);
            document.getElementById('lyric_area').innerHTML = sb.join('<br />')");

         // (省略)
     }, e => MessageBox.Show("Browser Error"))
     .Tap(disposables.Add);

歌詞の表示といっても、WebBrowserに表示しているこということは、歌詞のURLを渡すだけです。それだけで済むはずでした。が、……妙に複雑怪奇です。歌詞のURLが渡されて表示が完了してからが起点として(Navigated)、処理を開始しています。

何故こうなったか。WP7が現在積んでるIEは7。ついでにFlashはまだ未対応で見れません。それとこれとがどう関係あるかというと、歌詞表示に関係あります。日本の歌詞サイトは大抵はコピペ禁止のために右クリック禁止、だけでなく、Flashで表示していたりします。それじゃあ手が出せない。では今回利用しているgoo歌詞は、というと、少し変わっていてHTML5 Canvasに描画しています。勿論Canvasは古いブラウザじゃ動かないので、互換用JavaScriptも挟んでいるよう。uuCanvas.js を使っているようですが、環境貧弱なWP7版のIE7じゃあ、土台動きませんでした。

このまんまじゃあ歌詞が表示出来なくて困ったわけですが、幸いgoo歌詞はJSONPで歌詞データを別途取得してCanvasにデータを流しているようなので、HTMLからJSONPの発行先を割り出して、歌詞データを頂いてしまえば問題ない(この時点で規約的にはグレーな気が)。生の歌詞データが手に入ってしまっ……。こいつをキャッシュするようにしてオフラインでも見れるといった機能を提供してあげられれば幸せになれるのですが、そういうのは利用規約に違反、してますね、明らかに。

じゃあどうするか。手元には歌詞の表示されていないブラウザ上のHTMLと、歌詞データがある。よし、じゃあブラウザにこちらからはめ込んでやればいいんじゃなイカ?

WP7ではWebBrowserのDOMは触れません。DOMを外から触ってappendChildしてサクッと終了、というわけにはいかず。ただ、外部から干渉出来る口が一つだけ用意されています。それがInvokeScript。外から実行関数を指定して、戻り値を受け取れます(DOMは無理なので、Stringで貰うのが無難)。ならば、evalして外から実行関数自体を注入してやれば、何だって出来る。どうにも馬鹿らしい気もしますが、このぐらいしか手がないのでShoganai(なお、予めWebBrowserのプロパティでスクリプト実行を許可しておかないと例外が出ます)。

Timer and Polling

イベント(Navigated)→タイマー(SaveToString)→非同期(DownloadStringAsync)という直列の合成でした。直列の合成を行うメソッドはSelectMany(もしくはSelect+Switch、両者には若干の違いがあるのですが、それに関しては後日説明します)で、Rxの中でも頻繁に使うことになるメソッドです。

ところで、タイマーが唐突なのですが、何故タイマーを仕込んでいるのか。どうもNavigated直後にSaveToString(WebBrowser内のHTMLを文字列化)だと、タイミング次第で上手く抽出できないことが多かったので(JSで色々処理されてる影響かな?)、必要なJSONPの書かれた属性が取れるまでSaveToStringをリトライするようにしました。つまり、ポーリング(定期問い合わせ)です。

ポーリングは普通だと面倒くさいはずなんですが、Rxだと恐ろしく簡単に書ける上に、こうして通常の処理の流れと合成することが可能になっているのが何よりも強力です。.NET Frameworkには幾つものTimerクラスがあって、何を使えばいいのかと戸惑ってしまうところがありますが、答えは出ました。Observable.Timerがベスト。大変扱いやすい。

これで、本来Canvasのあった領域にテキストデータとして歌詞を表示させられました。全く違和感のない、完璧なハメコミ合成。無駄なコダワリです。地味すぎて一手間かけてることなんてさっぱり分からない。だがそれがいい。……いや、ちょっと悲しい。それにしてもでしかし、Canvas, Flash対応になればこんなやり方は不要になるわけで、今年後半のアップデートでのIE9搭載が待ち遠しい。

Unit Testing

Silverlight向けのユニットテスト環境って、全然ない。ブラウザ上のSilverlightで動かす、というタイプは幾つかありますが、Visual Studioと統合された形のでないと、そんなのアタシが許さない。

TDDするわけでも、熱心にテスト書くわけでも、特段カバレッジを気にするわけでもない私ですが、テストが書けることは重要視しています。何故かというと、メソッドの動作確認が最も素早く行えるから。テスト(が出来ること)に何を期待しているかというと、確認したいんです、メソッドの動作を。手軽に、コンソールアプリを書く感覚で、素早く。処理をコンソールアプリにコピペって、もしくは並走してコンソールアプリを立てながら開発していたりなどを以前よくしたのですが、それを単体テストのメソッド部分に書けば、動作確認のついでに、テストまで手に入るので、それは素敵よね?と。

(単体)テストが第一の目的ではない、(動作確認)テストが目的なのだ。だから、テストフレームワークはVisual Studioと完全な統合を果たしていなければならない。ショートカットでIDE内のウィンドウで即座に実行。スピードが大事。また、シームレスなデバッグ実行への移行も。故にMSTestを選択するのである(キリッ

などなどはその辺にしておいて、それはともかくで、素直にフル.NET Frameworkで動くMSTestを使います。一応Silverlightのアセンブリはフル.NETからも参照可能のようなので、普通にテストプロジェクトを立ててDebug.dll を参照してやる(プロジェクト参照は警告出るので)という手も使えなくはなさそうなのですが、完全な互換を持つコアライブラリは全体のごく一部で、それ以外を使っていると普通に実行時例外でコケるなど、正直使えないと私は判断しました。よって、アセンブリ参照でやるのは諦め。プロジェクト参照で警告が出る理由も分かりました、あまり実用的な機能ではない……。

代わりにWP7プロジェクトとテストプロジェクトの間に、.NET4ライブラリプロジェクトを立てて、「追加->既存の項目->リンクとして追加」で、フルフレームワークとWP7間で.csファイルを共有してやります(Viewは勿論共有出来ないので、基本はModelのみ)。

勿論、コードレベルで互換が取れていないと動きません。そんなわけで、少なくともModelに関してはWPF/SL/WP7で共通で使いまわせるように意識して作りたいところです。移植性というだけじゃなく、MSTestの恩恵を受けれるので。ただまあ、無理な部分は無理で諦めちゃってもいいとは思います(SLのほうにだけあるクラスとかもありますから)。非同期のテストなどは、幸いRxを使っていれば非常に簡単なので、バシバシ書いちゃいましょう。

// Utakotoha.Test/SongTest.cs
[TestMethod]
[Timeout(3000)]
public void SearchLyric()
{
    var song = new Song("吉幾三", "俺ら東京さ行ぐだ");
    var array = song.SearchLyric().ToEnumerable().ToArray();

    array.Count().Is(1);
    array.First().Title.Is("俺ら東京さ行ぐだ 吉幾三");
    array.First().Url.Is("http://music.goo.ne.jp/lyric/LYRUTND1127/index.html");
}

ToEnumerableしてToArrayするだけです!非同期のテストなんて怖くない。

Portable Library Tools CTPという、各環境で互換性の取れるライブラリが作成出来るもの、なども出てきているので、リンクで追加とかいう間抜け(そして面倒)なことじゃなく、プロジェクトごと分離して、Modelは互換で生成、というのが将来的には良いやり方になるかなあ、などと思っています。そういう事情から、私は移植性とは関係ない立場からも、Portable Library Toolsの発展に期待しています。

なお、アサーションはChaining Assertion使っています。ドッグフードドッグフード。というかもう、必需品なので、これないと書けない、書きたくない……。

Mocking Event with Moles and Rx

さて、このやり方の利点として、PexやMolesが使えます(Pexは一応SLをサポートしたものの、Molesは依然としてSL未サポート)。Moles(Microsoft Researchが提供するモックフレームワーク、フリー)の乗っ取り機構は強力なので、テスト可能範囲が大幅に広がります。詳しくはRx + MolesによるC#での次世代非同期モックテスト考察をどうぞ。

今回Linq to Eventで紹介したPlayingSongActiveは、以下のようにテストしています。MediaPlayer周りはXNAなので、Test側の参照DLLとしてXNA Game Studio v4.0のMicrosoft.Xna.Framework.dllを参照。そしてMolesで乗っ取り。

// Utakotoha.Test/MediaPlayerStatusTest.cs

private MediaPlayerStatus CreateStatus(MediaState state, string artist, string name)
{
    return new MediaPlayerStatus
    {
        MediaState = state,
        ActiveSong = new Microsoft.Xna.Framework.Media.Moles.MSong
        {
            NameGet = () => name,
            ArtistGet = () => new MArtist
            {
                NameGet = () => artist
            }
        }
    };
}

[TestMethod, HostType("Moles")]
public void PlayingSongActiveTest()
{
    // event invoker
    var invoker = new Subject<MediaPlayerStatus>();
    MMediaPlayerStatus.MediaStateChanged = () => invoker;

    // make target observable
    var target = MediaPlayerStatus.PlayingSongActive().Publish();
    target.Connect();

    // at first, stopped
    using (target.VerifyZero())
    {
        invoker.OnNext(CreateStatus(MediaState.Stopped, "", ""));
    }

    // next, playing
    using (target.VerifyOnce(song => song.Is(s => s.Title == "song" && s.Artist == "artist")))
    {
        invoker.OnNext(CreateStatus(MediaState.Playing, "artist", "song"));
    }

    // pause
    using (target.VerifyZero())
    {
        invoker.OnNext(CreateStatus(MediaState.Paused, "", ""));
    }

    // play again
    using (target.VerifyOnce(song => song.Is(s => s.Title == "song2" && s.Artist == "artist2")))
    {
        invoker.OnNext(CreateStatus(MediaState.Playing, "artist2", "song2"));
    }
}

元のコード自体がイベント発火部分はRxで包んであるので、そのイベント発火だけを差し替え。SubjectとはイベントのRxでの表現。OnNextでイベント発火の代用が可能になっています。これで、任意のイベント(今回はMediaPlayerなので、再生停止であったり再生開始であったり)を発行して、その結果の挙動を確認しています。

VerifyなんたらはIObservableへの自前拡張メソッドで、発火されたか/回数の検証です。「イベントは発生したけれどフィルタリングされて値が届かなかった」ことの、フィルタリングが正常に出来たかの確認って、そのままだと難しい。如何せんSubscribeまで届いてくれないということですから。そのため、その辺を面倒みてくれるものを用意しました。

// Utakotoha.Test/Tools/ObservableVerifyExtensions.cs

/// <summary>verify called count when disposed. first argument is called count.</summary>
public static IObservable<T> Verify<T>(this IObservable<T> source, Expression<Func<int, bool>> verify)
{
    var count = 0;
    return source
        .Do(_ => count += 1)
        .Finally(() =>
        {
            var msg = verify.Parameters.First().Name + " = " + count + " => " + verify.Body;
            Assert.IsTrue(verify.Compile().Invoke(count), "Verifier " + msg);
        });
}

/// <summary>verify called count when disposed. first argument is called count.</summary>
public static IDisposable VerifyAll<T>(this IObservable<T> source, Expression<Func<int, bool>> verify, Action<T> onNext = null)
{
    return source.Verify(verify).Subscribe(onNext ?? (_ => { }));
}

/// <summary>verify not called when disposed.</summary>
public static IDisposable VerifyZero<T>(this IObservable<T> source)
{
    return source.VerifyAll(i => i == 0);
}

/// <summary>verify called once when disposed.</summary>
public static IDisposable VerifyOnce<T>(this IObservable<T> source, Action<T> onNext = null)
{
    return source.VerifyAll(i => i == 1);
}

usingによるスコープを抜けるとFinallyで検証が入ります。RxでイベントをラップするとIDisposableになる、そのことの利点が生きてきます。

今後の改善

Pivotのヘッダーのデザインがどうも間抜け(マージンの取り方が変だし文字サイズも違和感あり)なのが気になってるので、変えたいです。HeaderTemplateの編集の仕方がよくわからずで放置なのですけれど、ゆったり紐解けば出来るでしょう。多分。

レジュームへの配慮が全くなくて、別画面にいくと真っ白になるのがビミョい。WebBrowserが絡むので完全な復元は無理だから、いっかー、とか思ったのが半分はあるのですが、いやまてその理屈はオカシイ。ので、ちょっと何とかさせないとですね。

xaml.csのコードが全体的にマズい。特にOAuth認証の部分はありえない強引さなのでとっとと変更。あと、もう少し適切な分割。MVVMはわからんちん。

Settingsが何か変。IsolatedStorageSettingsというか、その内部のDataContractSerializerの都合というか。これだ!というやり方ないかしら。今のやり方は、非常に間抜け。

ブラウザ画面黒背景はビミョーなので、設定でアプリ全体を白背景に変更するオプションを入れるのもいいかなー。それとアプリ起動時は楽曲を再生中でも自動検索しないのだけど、自動検索してくれたほうが嬉しいかなー。など、細かい点では色々考えること、追加することあります。

まとめ

上手く決まった部分しか解説してないので、実際のコードは残念ながらスパゲッティです:) というか、UI絡みのコードってほとんど書いたことないので、経験の無さが如実に現れていて苦すぃ。WP7で勝手がわからないというもの若干はありますが、それ以前の問題がかなり。サンプルアプリとしても、もう少し良くしたいので、コードは徐々に洗練させていきたいですます。

アプリとしては、まあまあいい出来というか、実用品として悪くないフィーリングだと思うのですが、どうでしょうか?画面周りは、このレイアウトで決まるまで何度も試して投げてを繰り返してこれに落ち着きました。実際に作りながら、試しながらでないとこういうの決められないよね。コードに関してもそうだけど。ともあれ、Pivotいいよねー。やはりWP7といったらPivot。

そんなわけで、RxはWP7開発のお供として欠かせない代物なので、是非使ってみてください。また、WP7で欠かせないということはSilverlightで欠かせないということであり、Silverlightで欠かせないということはWPFでも欠かせないということでも、あったりなかったりするので、Rxによるプログラミングパラダイムの変化を是非とも楽しんでみてください。Linq to Anything!

一記事に収めるため少々駆け足気味だったので、なにか不明な点、質問などありましたら気楽にコメントどうぞ。突っ込みも勿論歓迎です。

Microsoft MVP for Visual C#を受賞しました

Microsoft MVPから、Visual C#カテゴリで受賞しました。for Linqというカテゴリがないので大変厳しいかと思われましたが何とか認められたようです。活動申請には、ほんとうにLinqが~Linqが~ばかりで。今見返すと「活動の源泉は、C#/Linqの素晴らしさを伝えたい!ということです」などとコメント欄に書いちゃっていたり。あと、審査するのは本社の連中だからアメリカンに、大袈裟に書くぐらいがいいんだよ、とアドバイスを受けたので「RxJSによりJavaScriptにおいてもInterective(Enumerable)とReactive(Observable)の美しい融合が果たせることが可能となりました。そのうちのInterective側を支える(linq.js)ことが出来るのは自分しかいない」とかいう恥ずかしいことまで言っちゃってますね、うわあ。

というわけで、公約みたいなものなので、今後もC#/Linqの素晴らしさを伝える道を邁進したいと思います。

私とMVP。MVPアワードの存在を知ったのはXNEWSがマイクロソフトMVPアワードを受賞した時のことで、ただのゲーマーだった頃でした。その頃は何なのか分からず月日は流れ、就職してC#を触りだしてから(2008年)、MVPがどういう存在であるかを知り、以下略。

私が成長できたのは多くの先人の、ネット上のリソースのお陰です。今度は、私が恩返しする番。今まで通り、今まで以上に知識を伝えていけたらと思っています。

Prev | | Next

Profile

Yoshifumi Kawai

Cysharp, Inc
CEO/CTO

Microsoft MVP for Developer Technologies(.NET)
April 2011
|
July 2025

X:@neuecc GitHub:neuecc

Archive