StyleCop から 結果の XML を出力する

StyleCop - Home をインストールすると、VS に統合してくれて、VS でビルドすると警告を出してくれて便利なんですが、他のツールに連携する xml ファイルはどうやって吐くのかなと調べてみました。
参考にしたサイト
How to use StyleCop with TeamCity - Stack Overflow


とりあえず、プロジェクトを作成し、NuGet から StyleCop.MSBuild をインストールします。
これだけで、VS からビルドすると、出力ウィンドウ にStyleCop の警告が表示されるようになります。
この段階で .csproj ファイルには色々追加されてます。

.csproj 一部抜粋

  <PropertyGroup>
    <StyleCopMSBuildTargetsFile>..\packages\StyleCop.MSBuild.4.7.41.0\tools\StyleCop.targets</StyleCopMSBuildTargetsFile>
  </PropertyGroup>
  <Import Condition="Exists('$(StyleCopMSBuildTargetsFile)')" Project="$(StyleCopMSBuildTargetsFile)" />
  <PropertyGroup>
    <StyleCopMSBuildMessageMissing>Failed to import StyleCop.MSBuild targets from '$(StyleCopMSBuildTargetsFile)'. The StyleCop.MSBuild package was either missing or incomplete when the project was loaded. Ensure that the package is present and then restart the build. If you are using an IDE (e.g. Visual Studio), reload the project before restarting the build.</StyleCopMSBuildMessageMissing>
    <StyleCopMSBuildMessagePresent>Failed to import StyleCop.MSBuild targets from '$(StyleCopMSBuildTargetsFile)'. The StyleCop.MSBuild package was either missing or incomplete when the project was loaded (but is now present). To fix this, restart the build. If you are using an IDE (e.g. Visual Studio), reload the project before restarting the build.</StyleCopMSBuildMessagePresent>
    <StyleCopMSBuildMessageRestore>Failed to import StyleCop.MSBuild targets from '$(StyleCopMSBuildTargetsFile)'. The StyleCop.MSBuild package was either missing or incomplete when the project was loaded. To fix this, restore the package and then restart the build. If you are using an IDE (e.g. Visual Studio), you may need to reload the project before restarting the build. Note that regular NuGet package restore (during build) does not work with this package because the package needs to be present before the project is loaded. If this is an automated build (e.g. CI server), you may want to ensure that the build process restores the StyleCop.MSBuild package before the project is built.</StyleCopMSBuildMessageRestore>
    <StyleCopMSBuildMessageRestored>Failed to import StyleCop.MSBuild targets from '$(StyleCopMSBuildTargetsFile)'. The StyleCop.MSBuild package was either missing or incomplete when the project was loaded (but is now present). To fix this, restart the build. If you are using an IDE (e.g. Visual Studio), reload the project before restarting the build. Note that when using regular NuGet package restore (during build) the package will not be available for the initial build because the package needs to be present before the project is loaded. If package restore executes successfully in the intitial build then the package will be available for subsequent builds. If this is an automated build (e.g. CI server), you may want to ensure that the build process restores the StyleCop.MSBuild package before the initial build.</StyleCopMSBuildMessageRestored>
  </PropertyGroup>
  <Target Name="StyleCopMSBuildTargetsNotFound">
    <Warning Condition="!Exists('$(StyleCopMSBuildTargetsFile)') And $(RestorePackages)!=true And $(StyleCopTreatErrorsAsWarnings)!=false" Text="$(StyleCopMSBuildMessageMissing)" />
    <Warning Condition="Exists('$(StyleCopMSBuildTargetsFile)')  And $(RestorePackages)!=true And $(StyleCopTreatErrorsAsWarnings)!=false" Text="$(StyleCopMSBuildMessagePresent)" />
    <Warning Condition="!Exists('$(StyleCopMSBuildTargetsFile)') And $(RestorePackages)==true And $(StyleCopTreatErrorsAsWarnings)!=false" Text="$(StyleCopMSBuildMessageRestore)" />
    <Warning Condition="Exists('$(StyleCopMSBuildTargetsFile)')  And $(RestorePackages)==true And $(StyleCopTreatErrorsAsWarnings)!=false" Text="$(StyleCopMSBuildMessageRestored)" />
    <Error Condition="!Exists('$(StyleCopMSBuildTargetsFile)') And $(RestorePackages)!=true And $(StyleCopTreatErrorsAsWarnings)==false" Text="$(StyleCopMSBuildMessageMissing)" />
    <Error Condition="Exists('$(StyleCopMSBuildTargetsFile)')  And $(RestorePackages)!=true And $(StyleCopTreatErrorsAsWarnings)==false" Text="$(StyleCopMSBuildMessagePresent)" />
    <Error Condition="!Exists('$(StyleCopMSBuildTargetsFile)') And $(RestorePackages)==true And $(StyleCopTreatErrorsAsWarnings)==false" Text="$(StyleCopMSBuildMessageRestore)" />
    <Error Condition="Exists('$(StyleCopMSBuildTargetsFile)')  And $(RestorePackages)==true And $(StyleCopTreatErrorsAsWarnings)==false" Text="$(StyleCopMSBuildMessageRestored)" />
  </Target>
  <PropertyGroup>
    <PrepareForBuildDependsOn Condition="!Exists('$(StyleCopMSBuildTargetsFile)')">StyleCopMSBuildTargetsNotFound;$(PrepareForBuildDependsOn)</PrepareForBuildDependsOn>
  </PropertyGroup>

ここからが本番。StyleCop.targets を Import しているので、StyleCop のタスクが使えます。StyleCop.targets ファイル開き、Output で検索していくと、OutputFile を指定する StyleCopTask というのが見つかります。こいつを使って、.xml を出力します。
.csproj に 新しい Target を追加し、StyleCopTask を使って .xml を出力します。

.csproj の最後に OutputStyleCop(名前は何でも良い) ターゲットを追加します。

  <Target Name="OutputStyleCop">
    <!-- Create a collection of files to scan -->
    <CreateItem Include=".\**\*.cs">
      <Output TaskParameter="Include" ItemName="StyleCopFiles" />
    </CreateItem>
    <StyleCopTask 
      ProjectFullPath="$(MSBuildProjectFile)"
      SourceFiles="@(StyleCopFiles)" 
      ForceFullAnalysis="true" 
      TreatErrorsAsWarnings="true" 
      OutputFile="StyleCopReport.xml" 
      />
  </Target>
</Project>

この .csproj を MSBuild から /t:OutputStyleCop で蹴ると、StyleCopReport.xml が出力されます。

SortedList を List っぽく使う

ネタ。多分こんな使い方しないと思うけど、拡張メソッドで Add を追加してあげたらそれっぽくなるかも?

using System;
using System.Collections.Generic;

public static class SortedListExtensions {
  public static void Add<T>(this SortedList<int, T> target, T source) {
    target.Add(target.Count, source);
  }
}
class Program {
  static void Main(string[] args) {
    var sortedList = new SortedList<int, Item>();
    sortedList.Add(new Item() { Id = 2, Name = "かきく" });
    sortedList.Add(new Item() { Id = 1, Name = "あいう" });

    Console.WriteLine(sortedList[0]);
    Console.WriteLine(sortedList[1]);

    var list = new List<Item>() {
      new Item() { Id = 2, Name = "かきく" }, 
      new Item() { Id = 1, Name = "あいう" }
    };

    Console.WriteLine(list[0]);
    Console.WriteLine(list[1]);

    Console.ReadKey();
  }
}
class Item {
  public int Id { get; set; }
  public string Name { get; set; }

  public override string ToString() {
    return string.Format("Id:{0} Name:{1}", Id, Name);
  }
}

ODP.NET4 を使っているのに、.NET Framework 3.5SP1 が入っていない環境だとエラーが発生する。解決編

ODP.NET4 を使っているのに、.NET Framework 3.5SP1 が入っていない環境だとエラーが発生する - お だ のスペース
ODP.NET4 を使っているのに、.NET Framework 3.5SP1 が入っていない環境だとエラーが発生する。その 2 - お だ のスペース
の続きです。


ODP.NET4 required .NET2.0? | Oracle Forums に書き込みがあり解決しました。

C++ の再頒布可能パッケージを入れると解消します。
マイクロソフト公式ダウンロード センターから Microsoft Visual C++ 2005 SP1 再頒布可能パッケージ (x86) をダウンロード
言われてみれば納得ですね。


Oracle のドキュメント(システム要件)は、ちゃんと記載しといて欲しいなー。

ODP.NET4 を使っているのに、.NET Framework 3.5SP1 が入っていない環境だとエラーが発生する。その 2

ODP.NET4 を使っているのに、.NET Framework 3.5SP1 が入っていない環境だとエラーが発生する - お だ のスペース の続き
といっても大した事ではなくて、同じ現象の人が他にもいたよーって事です。


Oracle のフォーラムに投げてたんですが進展せずでしたが、同じ現象でたよーって方が出てきたので何か進展あるかも?
ODP.NET4 required .NET2.0? | Oracle Forums

Unity コンストラクタ インジェクションのメモ

config ではなくて、コードからコンストラクタインジェクションを指定する際のメモ
Registering Injected Parameter and Property Values では、値を直接指定する例は載ってたのですが パラメータ を Container から取る例が無かったのでメモ

using System;
using Microsoft.Practices.Unity;

class Program {
  static void Main(string[] args) {
    var container = new UnityContainer();
    container.RegisterType<IHoge, Hoge>()
      .RegisterType<Data>(new InjectionConstructor(typeof(IHoge), 10));
    var d = container.Resolve<Data>();
    Console.WriteLine(d.Val); // 10
    Console.WriteLine(d.Driver.Name); // Hoge
    Console.ReadKey();
  }
}

public interface IHoge { string Name { get; } }
public class Hoge : IHoge {
  string IHoge.Name { get { return "Hoge"; } }
}
public class Data {
  private readonly IHoge _driver;
  public IHoge Driver {
    get { return _driver; }
  }
  private readonly int _val;
  public int Val {
    get { return _val; }
  }

  public Data(IHoge hoge, int value) {
    _driver = hoge;
    _val = value;
  }
}

typeof(〜) で その型を渡すといけそうでした。

ODP.NET4 を使っているのに、.NET Framework 3.5SP1 が入っていない環境だとエラーが発生する

システム要件
ドキュメントのシステム要件では、.NET 4 or .NET4 Client Profile となっているんですけどねー。


実行環境

  • WindowsXP SP3
  • .NET Framework 4 Client Profile (.NET 2系は未インストール)
  • ODP.NET4

再現コード

using System;
using Oracle.DataAccess.Client;

class Program {
  static void Main(string[] args) {
    try {
      Console.WriteLine(typeof(string).Assembly.FullName);
      Console.WriteLine(typeof(OracleConnection).Assembly.FullName);
      var connStr = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=host)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=service name)));User Id=user;Password=pass;";
      using (var conn = new OracleConnection(connStr))
      using (var cmd = new OracleCommand(@"select SYSDATE from dual", conn)) {
        conn.Open();
        Console.WriteLine(cmd.ExecuteScalar());
      }
    }
    catch (Exception e) {
      Console.WriteLine(e.Message);
      Console.WriteLine(e.StackTrace);
    }            
    Console.ReadKey();
  }
}

実行結果

                                                                                                                                                              • -

mscorelib, Version=4.0.0.0, ...
Oracle.DataAccess, Version=4.112.3.0, ...
'Oracle.DataAccess.Client.OracleConnection' type iniitalize error ....

                                                                                                                                                              • -

Windows Update から .NET 3.5 SP1 をインストールすると発生せず。。

  • OraOps11w.dll version 2.112.3.0.
  • Oracle.DataAccess.dll version 4.112.3.0

ここらへんの違いが影響あるのかなー?
Windows7 (.NET 2系インストール済)だと発生しないので、.NET 2系が入ってるかどうかが肝だと思ってるですが。。

メモ:Unity の config ファイルのスキーマー

Unity は .NET の DI コンテナです。Unity Container


config ファイルのスキーマ
Unity 2.0
The Unity Configuration Schema
Unity 1.2
Unity Configuration Schematic


参考にした patterns & practices: Project Silk - Home では、1.2 の形式で書かれていました。
1.2 の形式でもエラーも出ず読み込んでくれていたので、スキーマが新しくなっていた事に今まで気付かず…。
2.0 の方がシンプルなので新しい方に書き直しました。