2013年7月27日土曜日

今ハズセナイ連載中漫画 (2013年夏版)

今楽しみにしている、連載中漫画リスト。春からいくつかの作品が完結しましたね。ってことで最新版に更新。
  • 週刊少年マガジン
    • あひるの空/日向武史
    • ベイビーステップ/勝木光
    • アゲイン!!/久保ミツロウ
    • 七つの大罪/鈴木央
    • 波打際のむろみさん/名島啓二
    • 我妻さんは俺のヨメ/蔵石ユウ・西木田景志
  • 週刊少年サンデー
    • 神のみぞ知るセカイ/若木民喜
    • マギ/大高忍
    • 銀の匙 Silver Spoon/荒川弘
    • 絶対可憐チルドレン/椎名高志
    • ハヤテのごとく!/畑健二郎
    • 最後は?ストレート!!/寒川一之
  • ヤングマガジン
    • センゴク一統記/宮下英樹
    • 雪にツバサ/高橋しん
    • エイト/楠みちはる
    • 8♀1♂/咲香里
  • ビックコミックスピリッツ
    • アイアムアヒーロー/花沢健吾
    • とめはねっ!/河合克敏
    • くーねるまるた/高尾じんぐ
    • あさひなぐ/こざき亜衣
    • 王様達のヴァイキング/さだやす
  • ビックコミックスペリオール
    • 人生画力対決/西原理恵子
  • モーニング
    • GIANT KILLING/ツジトモ・網本将也
    • 宇宙兄弟/小山宙哉
    • グラゼニ/森高夕次・アダチ ケイジ
    • ひらけ駒!/南Q太
    • 鬼灯の冷徹/江口夏美
    • ピアノの森/一色まこと
    • ライスショルダー/なかいま強
  • イブニング
    • 少女ファイト/日本橋ヨヲコ
    • いとしのムーコ/みずしな孝之
    • ADAMAS/皆川亮二
    • プロチチ/逢坂えみ子
    • Eから弾きな。/佐々木拓丸
  • アフタヌーン
    • ヒストリエ/岩明均
    • ヴィンランド・サガ/幸村誠
  • ゲッサン
    • MIX/あだち充
    • アオイホノオ/島本和彦
  • グランドジャンプ
    • 瞬きのソーニャ/弓月光
    • ぼくの体はツーアウト/よしたに
  • その他
    • もやしもん/石川雅之
    • 3月のライオン/羽海野チカ
    • ましろのおと/羅川真里茂
    • 白衣のカノジョ/日坂水柯
    • kiss×sis/ぢたま某
    • よつばと!/あずまきよひこ
    • WxY/マドカマチコ
完結してリストから削除されたのは、多分この4つ。
  • ジャポニカの歩き方/西山優里子
  • アントルメティエ/早川光・きたがわ翔
  • こどものじかん/私屋カヲル
  • 純潔のマリア/石川雅之
「ジャポニカの歩き方」は、以前のエントリで最終回についてちょっと書きましたね。「純潔のマリア」は終わったらしいんですが、単行本待ちです。2巻の終わりから後1冊でどうラストに持っていくのか楽しみ。

「こどものじかん」も小学校を卒業して終わりましたね。ただ、あのラストはいーのかしら?こうこうせいだよね…。しかも見た目変わらないってのがどうもなー。ともあれ、周りにお勧めできるかどうかはともかく、楽しく読めて考えることも多かったです。イイ漫画でした。

あとは「アントルメティエ」。これはなー。ちょっと残念なラストでした。面白かったと思うんだけどなー。


今回はこんな感じです。その他、リストに挙げてないけど楽しみにしているのも多いですし、最近始まったばかりで期待しているのもいっぱいあります。なんかしら、大化けして楽しみに育ってくれるモノが出てきてくれるとさらにうれしいなー。

FxCop カスタムルールの作成(配置と実行)

FxCop カスタムルールの作成(ビルドまで)」で作成したルールを実際に動かします。

本当はデバッガで動作を追っかけたいところですが、VS2012Expressではデバッガで外部ツール(プログラム)を実行させるのは難しいんですかね。残念ですがデバッガの使用はあきらめます。

ちなみに、Express以外の有償のエディションであれば、プロジェクトのプロパティで「デバッグ」を開き、「開始動作」を「外部プログラムの開始」に、「外部プログラムの開始」に「FxCopCmd.exe」へのパスを、「コマンドライン引数」に「/f:」に続いて静的分析したいアセンブリのフルパスを、さらに「/c」のスイッチを付けてコンソールに結果を出力させるようにしておくことで、作成したルールをデバッグできる「はず」です。

デバッグ時の注意点としては、VisualStudioもデバッグしたいルールアセンブリを読み込んでしまうので、修正して再配置するときは、VisualStudioを一度終了させる必要があります。面倒ですが仕方ない。

さて、ビルドしたルールアセンブリは、Program FilesのVSのフォルダの、「Team Tools\Static Analysis Tools\FxCop\Rules」のフォルダにコピーします。デバッグする場合は"pdb"ファイルも一緒にコピーします。

作成したルールアセンブリが、正しく動作するかどうかを確認するテスト用アセンブリも作っておきます。VS2012Expressで新規プロジェクトを作成し、クラスライブラリを作ります。名前は「DataTableRuleDummy」とでもします。

テスト用アセンブリには一つクラスを作ります。ルールがすべて引っかかるように、以下のようにしてみました。

public class Dummy
{
  private DataTable table;

  public Dummy(DataTable table)
  {
    this.table = table;
  }

  public int SumOfQuantity
  {
    get
    {
      int sum = 0;
      foreach (DataRow row in table.Rows)
      {
        sum += (int)row["qty"];
      }
      return sum;
    }
  }

  public int FirstOrder
  {
    get { return (int)table.Rows[0]["order"]; }
  }

  public void SetDone()
  {
    foreach (var row in table.Rows.Cast<DataRow>().Where(r => (int)r["f"] == 0))
    {
      row["f"] = 1;
      row["doneAt"] = DateTime.Now;
    }
  }
}

で、テスト用のアセンブリもビルドしておきます。

実行はここではFxCopのコマンド版で試してみます。GUI版やVisualStudioビルド統合版も多分動くはず。

コマンドプロンプトを起動し、以下のように入力します。(もちろん、実際は改行なしです。)

>"C:\Program Files\Microsoft Visual Studio 11.0\Team Tools\
Static Analysis Tools\FxCop\FxCopCmd.exe" /f:D:\Projects\Da
taTableRuleDummy\bin\Debug\DataTableRuleDummy.dll /c

これで実行してみると以下の結果となりました。



4つのルールがすべて出力されています。続いて、テスト用アセンブリを以下のように修正してビルド。その後もう一度FxCopを実行させてみます。

public class Dummy
{
  private DataTable table;

  public Dummy(DataTable table)
  {
    this.table = table;
  }

  public int SumOfQuantity
  {
    get { return table.AsEnumerable().Sum(r => r.Field<int>("qty")); }
  }

  public int FirstOrder
  {
    get { return table.AsEnumerable().First().Field<int>("order"); }
  }

  public void SetDone()
  {
    foreach (var row in table.Select("flag=0"))
    {
      row.SetField("flag", 1);
      row.SetField("doneAt", DateTime.Now);
    }
  }
}


DataTable関連の警告が出なくなりましたね。

と、とてもとても時間がかかりましたが、古式ゆかしきDataSetも、工夫次第でそれなりに使えるということを言いたかったのです。

あと、会社やプロジェクト単位でコーディングスタンダードを用意している場合、コードレビューでスタンダードに適合しているかをチェックするなんてのはやってらんないので、このようにFxCopのカスタムルールを一度作ってしまえば、スタンダードに適合しているか否かのチェックをFxCopに任せられるので、あとがずいぶん楽になります。このために参考になる方もいるのではないかなぁ。と思いました。

2013年7月26日金曜日

FxCop カスタムルールの作成(ビルドまで)

ADO.netのDataSetをLINQableに書くために (本題) ~ FxCopカスタムルールを作成する。」の続きです。今度こそカスタムルールを作ります。ただ、手元にVS2012Expressしかないので、これで作ります。

前エントリで書いたとおり、アセンブリを静的分析し、以下のパターンに適合する場合は警告を出すように作ります。

イマイチ好みじゃないずいぶんマシ
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拡張メソッドを使う。

VS2012Express(今回はDesktopを使いました。)を開き、新規プロジェクトを作ります。「クラスライブラリ」を選択し、プロジェクト名は「DataTableRules」とでもしておきましょう。


作成したプロジェクトに、FxCopのアセンブリを参照するようにします。プロジェクトの「参照設定」を右クリックし、「参照の追加」を選択します。

プロジェクト外の、GACにもない外部アセンブリを参照するので、「参照」ボタンをクリックします。
Program FilesのVSのフォルダの、「Team Tools\Static Analysis Tools\FxCop」にある2つのアセンブリファイル、「FxCopSdk.dll」と「Microsoft.Cci.dll」を選択して追加します。


作成したプロジェクトには、警告メッセージなどを管理するためのXMLリソースが必要になります。
ここでは「CustomRules.xml」というファイルをプロジェクトに追加します。プロジェクトを右クリックして「新規作成」-「追加」-「新しい項目」を選び、XMLファイルをプロジェクトに追加します。


  追加したXMLファイルはリソースとして扱います。ソリューションエクスプローラーで追加したXMLファイルを選び、プロパティで「ビルドアクション」を「埋め込まれたリソース」に変更します。


XMLの中身の編集は後でやります。

さて、前述の警告出力パターンですが、どうすれば検知できるかを考えてみます。

まず、「foeach構文でDataTable.Rowsプロパティを使う。」ですが、これは「DataTable.Rows.GetEnumerable」メソッドが使われたときに警告を出す。と考えればよさそう。

「DataTable.RowsプロパティにEnumerable.Cast<DataRow>拡張メソッドを使う。」は、そのまんま「Enumerable.Cast<DataRow>」静的メソッドが使われたときに警告を出すでオケ。

「DataRowCollectionクラスのインデクサを使う。」はインデクサの呼び出しですが、CLI的には「DataRowCollection.get_Item」メソッドが使われた時。という扱いになるようです。

「DataRowクラスのインデクサを使う。」も同様に、「DataRow.get_Item」または「DataRow.set_Item」メソッドが使われた時。となるようです。

これら4つのルールすべてにおいて、メソッドの呼び出しを確認することで検知可能ということになります。そこで、まずは基本となる抽象クラスを作ります。

プロジェクト作成時に作られるプレースホルダのクラス「Class1.cs」を使いましょう。まずはファイル名を「BaseDataTableRule.cs」に修正、クラス名もそれに合わせて変更します。内容は「すべてのメソッドを確認する」的な内容になっている…と思われます。なにせドキュメントが少なく、いろいろ試してうまくいっているだけなので、定かじゃないところも残ってます。

using Microsoft.FxCop.Sdk;

namespace DataTableRules
{
  public abstract class BaseDataTableRule : BaseIntrospectionRule
  {
    protected BaseDataTableRule(string name) : base(
      name, "DataTableRules.CustomRules", typeof(BaseDataTableRule).Assembly) {}

    public override ProblemCollection Check(Member member)
    {
      var m = member as Method;
      if (m != null)
        Visit(m);

      return Problems;
    }
  }
}

抽象クラスを作ったら、1ルールにつき1クラスとなるように、4つのクラスを作り抽象クラスから派生させます。まず「foeach構文でDataTable.Rowsプロパティを使う。」を検出するルール。「NoUseGetEnumeratorMethodToDataTableRows」としました。長いけどこのクラスを誰か人に使ってもらうわけではないので、今回は気にしない。名前がわかりやすいほうが重要。

using System;
using Microsoft.FxCop.Sdk;

namespace DataTableRules
{
  public class NoUseGetEnumeratorMethodToDataTableRows : BaseDataTableRule
  {
    public NoUseGetEnumeratorMethodToDataTableRows()
      : base("NoUseGetEnumeratorMethodToDataTableRows") {}

    public override void VisitMethodCall(MethodCall call)
    {
      var binding = call.Callee as MemberBinding;
      var target = binding.TargetObject;
      var member = binding.BoundMember;

      if (member.Name.Name == "GetEnumerator" && 
          target.Type.FullName == "System.Data.DataRowCollection")
      {
        Problems.Add(new Problem(GetResolution()));
      }

      base.VisitMethodCall(call);
    }
  }
}

2つめのクラスは「DataTable.RowsプロパティにEnumerable.Cast<DataRow>拡張メソッドを使う。」これを「NoUseCastMethodToDataTableRows」クラスとして実装します。(18行目と19行目に分けているのは、Web上で表示させるのに横長になりすぎるためで、本来分ける必要はありません。)

using System;
using Microsoft.FxCop.Sdk;

namespace DataTableRules
{
  public class NoUseCastMethodToDataTableRows : BaseDataTableRule
  {
    public NoUseCastMethodToDataTableRows()
      : base("NoUseCastMethodToDataTableRows") {}

    public override void VisitMethodCall(MethodCall call)
    {
      var binding = call.Callee as MemberBinding;
      var member = binding.BoundMember;

      if (member.FullName == 
        "System.Linq.Enumerable.Cast<System.Data.DataRow>"
        + "(System.Collections.IEnumerable)")
      {
        Problems.Add(new Problem(GetResolution()));
      }

      base.VisitMethodCall(call);
    }
  }
}

そして3つめのクラスは「DataRowCollectionクラスのインデクサを使う。」を「NoUseIndexerToDataTableRows」クラスとして実装します。

using System;
using Microsoft.FxCop.Sdk;

namespace DataTableRules
{
  public class NoUseIndexerToDataTableRows : BaseDataTableRule
  {
    public NoUseIndexerToDataTableRows()
      : base("NoUseIndexerToDataTableRows") {}

    public override void VisitMethodCall(MethodCall call)
    {
      var binding = call.Callee as MemberBinding;
      var member = binding.BoundMember;

      if (member.FullName.StartsWith(
         "System.Data.DataRowCollection.get_Item(", StringComparison.Ordinal))
      {
        Problems.Add(new Problem(GetResolution()));
      }

      base.VisitMethodCall(call);
    }
  }
}

そして4つめ。「DataRowクラスのインデクサを使う。」を「NoUseIndexerToDataRow」として実装します。

using System;
using Microsoft.FxCop.Sdk;

namespace DataTableRules
{
  public class NoUseIndexerToDataRow : BaseDataTableRule
  {
    public NoUseIndexerToDataRow() : base("NoUseIndexerToDataRow") {}

    public override void VisitMethodCall(MethodCall call)
    {
      var binding = call.Callee as MemberBinding;
      var member = binding.BoundMember;

      if (member.FullName.StartsWith(
            "System.Data.DataRow.get_Item(", StringComparison.Ordinal) ||
          member.FullName.StartsWith(
            "System.Data.DataRow.set_Item(", StringComparison.Ordinal))
      {
        Problems.Add(new Problem(GetResolution()));
      }

      base.VisitMethodCall(call);
    }
  }
}

あとはXMLリソースの中身の編集です。長いですが、こんな感じ。(適宜改行してます。)
<?xml version="1.0" encoding="utf-8" ?>
<Rules FriendlyName="データテーブルの使い方の規則">
<Rule TypeName="NoUseCastMethodToDataTableRows"
      Category="My.DataTable" CheckId="DT0001">
<Name>DataTable.RowsにCast&lt;DataRow&gt;()拡張メソッドを使用しません</Name>
<Description>可読性の向上のため、DataTable.RowsにCast&lt;DataRow&gt;拡張メソッド
を使用しません。</Description>
<Url />
<Resolution>DataTable.RowsにCast&lt;DataRow&gt;拡張メソッドが使用されています。
さらなる条件の絞り込みや、ソートが必要であればDataTable.Select()メソッドを、
そうでなければDataTable.AsEnumerable()拡張メソッドを使用してください。
</Resolution>
<Email />
<MessageLevel Certainty="80">Warning</MessageLevel>
<FixCategories>NonBreaking</FixCategories>
<Owner />
</Rule>
<Rule TypeName="NoUseGetEnumeratorMethodToDataTableRows"
      Category="My.DataTable" CheckId="DT0002">
<Name>foreach構文でDataTable.Rowsを使用した列挙を行いません</Name>
<Description>LINQとの親和性向上のため、DataTable.Rows.GetEnumerable()メソッドを
使用しません。</Description>
<Url />
<Resolution>DataTable.Rows.GetEnumerable()が使用されています。さらなる条件の
絞り込みや、ソートが必要であればDataTable.Select()メソッドを、そうでなければ
DataTable.AsEnumerable()拡張メソッドを使用してください。</Resolution>
<Email />
<MessageLevel Certainty="80">Warning</MessageLevel>
<FixCategories>NonBreaking</FixCategories>
<Owner />
</Rule>
<Rule TypeName="NoUseIndexerToDataTableRows"
      Category="My.DataTable" CheckId="DT0003">
<Name>DataTable.Rowsのインデクサを使用しません</Name>
<Description>可読性の向上のため、DataTable.Rowsのインデクサを使用しません。
</Description>
<Url />
<Resolution>DataTable.Rowsのインデクサが使用されています。テーブル内の各行を列挙
する場合には、DataTable.Select()メソッド、またはDataTable.AsEnumerable()拡張
メソッドを使用してforeach構文で列挙してください。 先頭行のみ取り出す場合には、
DataTable.AsEnumerable()拡張メソッドと、Enumerable.First()を使用して一時変数に
代入後、使用してください。
      例:var firstRow = dt.AsEnumerable().First();</Resolution>
<Email />
<MessageLevel Certainty="80">Warning</MessageLevel>
<FixCategories>NonBreaking</FixCategories>
<Owner />
</Rule>
<Rule TypeName="NoUseIndexerToDataRow"
      Category="My.DataTable" CheckId="DT0004">
<Name>DataRowのインデクサを使用しません</Name>
<Description>可読性の向上のため、DataRowのインデクサを使用しません。
</Description>
<Url />
<Resolution>DataRowのインデクサが使用されています。テーブル内の各行のカラムに値
を設定、または取得する場合は、DataRow.SetField&lt;T&gt;()拡張メソッド、および
DataRow.Field&lt;T&gt;()拡張メソッドを使用してください。</Resolution>
<Email />
<MessageLevel Certainty="80">Warning</MessageLevel>
<FixCategories>NonBreaking</FixCategories>
<Owner />
</Rule>
</Rules>

ふぅ。これで準備完了。のはず。後はビルド~配置~デバッグ。です。

が、もう限界。眠い。またまた続きにします。しくしく。いい加減終わらせたかったけどなぁ。

2013年7月18日木曜日

今週のマガジン

『ベイビーステップ』の完全に予想外な展開にびっくり。今後どう展開していくのか…。
あとは『我妻さんは俺のヨメ』がどんどん面白くなってきてます。今後さらに期待したい。

2013年7月12日金曜日

VS2012ExpressでFxCop(コマンドライン版)を実行する。

今僕がいじっているPCには、VisualStudio 2012 Express (VS Express) のWebとDesktopがインストールされていますが、FxCopのコマンドライン版はすでに入っていました。



最初から入っていたかどうかは謎ですが…。深く追求はしないことにして、こいつが動くかどうかを確認しておきます。

コマンドプロンプトを起動し、FxCopCmd.exeを実行します。/f オプションで分析対象のアセンブリをフルパスで、また、結果をコンソールに出力させるため、/c オプションも付けて実行。



あれ?途中までうまくいったと思ったらエラーが出た。「Xslファイルが無ぇ」と来たか。

確かにエラーメッセージを見ると、上のエクスプローラで示したフォルダに、「Xml」フォルダが無いとおかしいのかな?

うーん。そんなもんなのか。でも探せばどっかにあるんじゃないか。と思ったら果たしてありました。このリンク先がいつまであるかも謎ですが、とりあえず貼っておく。

https://trac.openstreetmap.org/browser/applications/utils/Srtm2Osm/trunk/lib/Microsoft%20FxCop%201.36/Xml/VSConsoleOutput.xsl?rev=6526

謎のTracサイトですが、このXslはそれっぽい。リンク先のページの下のほうにある、「Download in other formats / Original Format」のリンクから、「VSConsoleOutput.xsl」ファイルをダウンロードし、FxCopのフォルダに「Xml」サブフォルダを作ってそこにコピー。

その後さっきと同じコマンドを実行した結果。





うん。これでOK。特にSDK+FxCopを別途インストールしなくとも、コマンドラインのFxCopならExpressでも動作させられるようですね。…Xslファイルを一つ謎のサイトから持ってきたことを除けば、まぁ、問題はないと言えるような気がしなくもないかな。



…で、ここまでできるならビルドにFxCopも統合して、FxCopのメッセージをビルド時にワーニングとして出すようにできるんじゃないかと思い、いろいろ試行錯誤してみましたが、今のところできて無いです。MsBuildのフォルダにはFxCop用のターゲットファイルもあったし、.csproj のファイルに<CodeAnalysisTarget>を書けばいけるんじゃないかと思ったんですが、甘かった。

どなたかVS2012Expressで、FxCopをビルドに統合できた方。もしいたら教えていたいただきたいなー。なんて。

2013年7月10日水曜日

今週のイブニング

今週も色々面白かった。中でも出色は「さよならタマちゃん」最終回でした。

この漫画、連載開始当初はまるで期待せずに読んでたんですが、途中から格段に面白くなってきて、ここしばらくはとても楽しみにしていました。絵も好みです。

で、今回の最終回。電車のなかで読んだんですが、感情の起伏が激しくて、泣きそうになるのを我慢しながら読んでました。

しかし、漫画読んで泣くなんて久しぶり。記憶にある限りだと、「赤ちゃんと僕」以来。多分。

イブニングで25回の連載。ということは、ほぼ一年連載してたんですね。お疲れ様でした。

さて。次はどんな漫画を読ませてもらえるのか。楽しみに待ちまーす。

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のカスタムルールを作ろうと思います。

えーと、続きます。

2013年7月6日土曜日

今週のモーニング

「カレチ」が最終回でした。どう考えてもグッドエンドにはなりそうにない展開でしたが、なんとか鬱にならずに済みましたかね。

面白かったです。お疲れ様でした。

さて、次はどんな漫画を読ませてもらえるのかが気になりますね。