user.config ファイルを探す : または実用的な LINQ サンプル

クライアントで動く .NET アプリのアプリケーション設定で、ユーザースコープなデータを定義すると user.config ファイルに記録されます。この user.config ファイルを探して列挙するコードを書きました。id:siokoshou:20071227#p1 のファイル列挙のサンプルとしてどうぞ。
ApplicationSettingsBase.Upgrade() をオーバーライドするときや、よそのアプリの user.config を見たいときなどに使えます。

user.config の FileInfo を列挙して返します。バージョンが新しいものから古いものへ、同じバージョンがあれば(署名してないと実行ファイルのパスを変えると user.config は異なるディレクトリに記録される)書き込み時刻が新しいものから古いものへ、という順に並べて返します。LINQ でさらに絞り込みも楽々です。
company と product は、対象アプリの AssemblyCompany と AssemblyProduct で指定した文字列を入れてください。

public static IEnumerable<FileInfo>
  SearchUserConfig( string company, string product )
{
  if ( company == null )
    company = "";

  var path = Path.Combine(
    Environment.GetFolderPath( Environment.SpecialFolder.LocalApplicationData ),
    company );
  var dir = new DirectoryInfo( path ).GetDirectories(
    product + "*" );

  var files = from d in dir
    from f in d.EnumFileSystemInfos().OfType<FileInfo>().Where( ff => ff.Name == "user.config" )
    where f.Directory.Name.Count( c => c == '.' ) == 3
    orderby new Version( f.Directory.Name ) descending, f.LastWriteTimeUtc descending
    select f;

  return files;
}

public static IEnumerable<FileSystemInfo>
  EnumFileSystemInfos( this DirectoryInfo dir )
{
  foreach ( var item in dir.GetFileSystemInfos() )
  {
    yield return item;

    var subDir = item as DirectoryInfo;
    if ( subDir != null )
    {
      foreach ( var subItem in subDir.EnumFileSystemInfos() )
      {
        yield return subItem;
      }
    }
  }
}

EnumFileSystemInfos() は nsharp さんのものをちょっと改造したもの。LINQ 登場でなんでも列挙してしまえば楽に扱えるようになりましたね。いろんなものを列挙して LINQ で扱うアイデアがあちこちで出てくることを期待してます。
EnumFileSystemInfos() を使っているので、標準の user.config が作られるディレクトリより深い階層に退避してあるような user.config ファイルも見つけてしまうのでご注意を。メリットでもあると思ったのでそのまま載せましたが、このロジックで困る場合は改造して使ってください。
よそのアプリの user.config を読みたい場合に System.Configuration 名前空間を使う方法もありますが、特にメリットもないので↑のコードでファイルを見つけて LINQ to XML で中身を読むのがおすすめです。苦労して ConfigurationManager.OpenMappedExeConfiguration あたりを調べたのに、面倒なだけで特にメリットがなかった…(T-T)
先週は System.Configuration と格闘してました。ここのドキュメントは酷すぎるので、疲れた…。

追記
LINQ 登場前はこういう新規性も何もないつまらない部分のコーディングって、モチベーションが上がらなくてぐずぐずして取り掛かれなかったんだけど、LINQ 登場でさっと書けるようになったし、LINQ で書くとどうなるかな?って部分が楽しいのでさっさと取り組めるようになりました。LINQ いいよ〜。

  • 2008/3/10 サンプルコードのエラー耐性を強化しました。
  • 2008/3/10 エラー耐性強化が一部まずかったので修正。