その後いくつかのエントリで、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");
Enumerable.Cast<DataRow>を使ってLINQの各種メソッドに繋ぐこともできますが、専用の拡張メソッドAsEnumerableを使ったほうがわかりやすいと思います。あるいは、さらにWhereやOrderByで絞り込みや並べ替えが必要なら、DataTable.Selectメソッドのほうが高速なケースが多いです。(Selectメソッドの名前が気に入らないですが、仕方ないと思ってます。)
というわけで、上にあげた4種類の「イマイチ好みじゃない」コードを見つけた時に、コンパイル時点で警告を出すFxCopのカスタムルールを作ろうと思います。
えーと、続きます。
0 件のコメント:
コメントを投稿