概要

1章(『プログラミング C#』 その1 C# の基礎)でこんなユニットテストコードを読んだけど……

// テストコード
namespace HelloMidori.Tests
{
    [TestClass]    // ←これ!
    public class UnitTest1
    {
        private string _consoleOutput;

        [TestInitialize]    // ←これも!
        public void Initialize()

こん中の [TestClass] とか [TestInitialize] って書いてるところが、属性を利用しているところみたいだぜ。あーわかるわかる、これは自信があるぞ、これはゼッテー、 Python でいうところのデコレータだろう!

 

流し読みノート

こいつらは属性という

  • これらは実際には TestClassAttribute みたいなクラスで、利用するときは Attribute を省略できるってわけだ(省略しなくてもよい)。
  • クラスだから、引数をとるコンストラクタをもつこともできて、そういうときはこんなふうに利用したりする。→ [TestCategory("Property Handling0")]
  • コンストラクタ引数だけでなく、プロパティで制御する属性もある。多数のオプション設定があるときはコンストラクタではなくプロパティによる制御が妥当。こんなふうに。→ [ExpectedException(typeof (ArgumentException), AllowDerivedTypes = true)]
  • 属性は、こないだリフレクション API にあった、型システムのあらゆる部分につけることができる。ということはクラスやメソッドだけじゃなく、アセンブリやモジュールにもつけられるということだ。
// アセンブリレベル。
[assembly: AssemblyCompany("Interact Software Ltd.")]
[assembly: AssemblyProduct("属性ターゲットの例")]
[assembly: AssemblyCopyright("Copyright c 2012 Interact Software Ltd.")]

// モジュールレベル。
using System.Diagnostics;
[module: Debuggable(DebuggableAttribute.DebuggingModes.DisableOptimizations)]
  • 実行時に CLR から特別扱いをうける属性もある。それを網羅したリストは公式には存在しないらしい……隠し要素だ!
// internal アクセシビリティは本来アセンブリ外からは参照できないけど、できるようにする属性。
[assembly: InternalsVisibleTo("ImageManagement.Tests")]
  • ↑この InternalsVisibleTo は1章ではじめに出くわした問題に解決方法をくれる。(そんなのあったっけ?)
    • もともと Program クラスは internal だったのだけど、テストから見れないから public にしていたのだ。
    • InternalsVisibleTo を使えば internal のままにしておける。
// メインプログラム
namespace HelloMidori
{
    internal class Program  // こうしておける!!?
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello, Midori!");
        }
    }
}

 

属性のうんちく

  • CLR はオブジェクトをシリアル化できる。
    • シリアル化ってのは、バイナリストリームにオブジェクトのフィールドの値をすべて書けることをいうらしい。そうなん?
    • SerializableAttribute を使うとバイナリストリームへ値を書く許可を CLR に与えられる。
  • SecurityCriticalAttribute とか SecuritySafeCriticalAttribute は、信頼されていないコードがそのメソッドを呼べるかどうかを設定する。そんな要素があるんだなあ。(小並感)
  • MethodImplAttribute は JIT コンパイラのコード生成に影響を及ぼす。よくわからんけど関数呼び出しは「驚くほど重い」という問題を解決するらしい。え? じゃあ最初から全部のメソッドにつけておけばいいじゃん、よくわからん。
  • 「カスタム属性」という言葉って、我々が新規で作る属性クラスのことかと思ったんだけどそういうわけでもないみたい。
    • カスタム属性は、メタデータフォーマットの中で特別な固有の処理を持たない属性のことだそうだ。(?)
    • .NET Framework クラスライブラリの中の、 Microsoft が書いた属性の多くもカスタム属性なんだって。
    • いやあ……こんなネーミング定義に意味はあるのだろうか。
  • 属性は先日読んだリフレクション API と利用するシステムでもっとも有効なんだって。でもてんで興味がわかなかったのでそこはスキップ。

 

小休憩

これはゼッテー、 Python でいうところのデコレータだろう!

うん、違うっぽいすね。デコレータはメソッドの改造だ。 C# の属性は、アセンブリのメタデータにカスタムデータを埋め込むものだ。

リフレクションのときに知ったけど、アセンブリには型のメンバや実装の詳細が含まれたメタデータが入っている。属性はそこにデータを追加できるということだ。リフレクション API はそれにアクセスできる。そう考えるとその両者が相性いいっていうのはわかるね。まあよくわからずスキップしたけど。