カスタム属性とRealProxy

便利だけどあんまり使われていないので、使用例をちょっと紹介。

開発中に#ifdef DEBUGでトレース埋め込んだりすることがあると思います。良くあるパターンとしてメソッド名や引数、時間などを書き出すと思いますが、単純作業で退屈ですし、ソースコードが読みにくくなってちょっと嫌です。そんなの時に、カスタム属性とRealProxyを使うと便利です。

こんなクラスがあったとします。

class MyClass : ContextBoundObject {
  public double Add(double x, double y) {
    return x + y;
  }
  public void Multiply(double x, double y, out double z) {
    z = x * y;
  }
  public double Divide(double x, double y) {
    if (x < double.Epsilon) {
      throw new DivideByZeroException("Exception message");
    }
    return x / y;
  }
}

足し算、掛け算、割り算メソッドを持っています。このメソッドが呼ばれる度にログを残したい、出来れば例外の発生もサポートしたいとします。

クラスの先頭に属性を付けると・・・

// ロギング属性をつける
[MethodCallLogging(null)]
class MyClass : ContextBoundObject {
// 略
}

こんな感じに動いて欲しい。

// テスト
class LoggingTest {
  [STAThread]
  static void Main(string[] args) {
    MyClass my = new MyClass();
    double z;
    // inパラメータと戻り値の例
    my.Add(1.23, 4.56);
    // in,outパラメータの例
    my.Multiply(9.87, 6.54, out z);
    try {
      // 例外発生の例
      my.Divide(0, 0);
    }
    catch (Exception) {
      // do nothing
    }
  }
}

/* 実行結果
<Add start="2004/03/29 1:21:46" time="00:00:00.7031250">
        <in><x>1.23</x><y>4.56</y></in>
        <out></out>
        <return>5.79</return>
</Add>
<Multiply start="2004/03/29 1:21:46" time="00:00:00.9062500">
        <in><x>9.87</x><y>6.54</y></in>
        <out><z>64.5498</z></out>
        <return>System.Void</return>
</Multiply>
<Divide start="2004/03/29 1:21:47" time="00:00:00.1250000">
        <in><x>0</x><y>0</y></in>
        <exception type="System.DivideByZeroException">Exception message</exception>
</Divide>*/

こんなうまい話があったりするのが、カスタム属性とRealProxyです。完全な実装については、ここを参照ください。もし、使えそうでしたら、カット&ペーストして持って行って下さい(笑)。

以前から公開していたのですが、ログがXML形式になってないのがずっと気になっていたので、今回修正しました(^^;