2013年7月8日月曜日

ADO.netのDataSetをLINQableに書くために (本題) ~ FxCopカスタムルールを作成する。

ADO.netのDataSetをLINQableに書くために (前段)」では、『型無しデータセットを使う場合は、コードのメンテナンシビリティを保つためにルールを制定する』こと、そして、『開発にあたってのルールを強制する方法を考えた時、「FxCop」と「StyleCop」の2つのツールが有用』と書きました。

その後いくつかのエントリで、FxCopとStyleCopについて書いてみて、いよいよカスタムルールを作ってみようと思います。

今回はFxCopのカスタムルールを作ります。StyleCopではなくFxCopを選んだのは、いくつかのカスタムルールを生成する方法を説明したサイトを見てみて、こちらのほうが作るに容易そうだ。という点と、FxCopで十分要求する内容が作れそうだ。と考えたことによります。

FxCopのカスタムルールの生成方法について、以下の2つのサイトを参考にさせていただきました。ありがとうございます。


さて、過去いろんなプロジェクトのソースを眺めてきましたが、DataSetを使ったコードで、大変気になるのが以下のようなケース。これらは、DataSetの各種拡張メソッド等を使うことで、だいぶキモチワルサが緩和されると思っています。


イマイチ好みじゃないずいぶんマシ
foeach構文でDataTable.Rowsプロパティを使う。DataTable.AsEnumerable拡張メソッドまたはDataTable.Selectメソッドを使う。
LINQを使うために、DataTable.Rows拡張プロパティにEnumerable.Cast<DataRow>拡張メソッドを使う。DataTable.AsEnumerable拡張メソッドまたはDataTable.Selectメソッドを使う。
DataRowCollectionクラスのインデクサを使う。DataTable.AsEnumerable拡張メソッドまたはDataTable.Selectメソッドを使う。(インデクサは使わない。)
DataRowクラスのインデクサを使う。DataRow.Field拡張メソッドDataRow.SetField拡張メソッドを使う。

たとえば、よくあるこんなコード(イマイチな例その1)。
foreach (DataRow row in table.Rows)
{
  sum += (int)row["order"];
  row["flag"] = 0;
  row["doneAt"] = DateTime.Now;
}

これをこう変えることで、後にリファクタリングするときにLINQを利用しやすくしたり、あるいはコンパイラによる型のチェックをフォローしてもらえるようになるメリットがあります。
foreach (var row in table.AsEnumerable())
{
  sum += row.Field<int>("order");
  row.SetField("flag", 0);
  row.SetField("doneAt", DateTime.Now);
}

あるいはよく見かけるのは、SELECTで1行のみにヒットするようにしたときのコード(イマイチな例その2)。
data.order = (int)table.Rows[0]["order"];
data.name = (string)table.Rows[0]["name"];
data.flag = (int)table.Rows[0]["flag"];

これはこう書くとまだすっきりします。
var firstRow = table.AsEnumerable().First();

data.order = firstRow.Field<int>("order");
data.name = firstRow.Field<string>("name");
data.flag = firstRow.Field<int>("flag");

また、DataTable.Rowsプロパティ(DataRowCollectionクラス)は、IEnumerableは実装しますが、IEnumerable<DataRow>を実装しないので、そのままではLINQの各種メソッドを使えません。

Enumerable.Cast<DataRow>を使ってLINQの各種メソッドに繋ぐこともできますが、専用の拡張メソッドAsEnumerableを使ったほうがわかりやすいと思います。あるいは、さらにWhereやOrderByで絞り込みや並べ替えが必要なら、DataTable.Selectメソッドのほうが高速なケースが多いです。(Selectメソッドの名前が気に入らないですが、仕方ないと思ってます。)

というわけで、上にあげた4種類の「イマイチ好みじゃない」コードを見つけた時に、コンパイル時点で警告を出すFxCopのカスタムルールを作ろうと思います。

えーと、続きます。

0 件のコメント:

コメントを投稿