透過プロキシを使用したメソッド呼び出しのロギング

C# / SqueezeSample1.zip

6年前の id:ladybug:20041008 から何も変わっていませんが、せっかくなので実行できる形のサンプルを書きなぐってみた。書きなぐりなので、ちゃんと動いてない部分があるかもしれません。
もともと、ContextBoundObject が Generics を含むクラスをサポートしていないという話*1 からなのですが、そういえば動くソースコードがないなと思って、ざっくり書き直してみました。
DynamicObject は透過プロキシの代わりとして十分な機能を持つと思いますが、メタデータの扱いが一般のクラスと同じであるため型に互換性がなくてソースコード的な細工が必要になることや、インテリセンス等の恩恵を得られないなどの問題があります。DynamicObject の関連クラスにはメタデータ関連のものもあるのですが、それらは DLR を活用した言語のためのものであって C# での利用には向かない*2と思われるので、ふつうに透過プロキシです。

まあ、透過プロキシの場合は、ContextBoundObject と違って仕組みがリモーティングのためにあるので、外から中へのアクセスだけしか検出できないのが難点ですね。他の方法としては、

  • 自分で自分の ICorlib だったかにアタッチしてプロファイリング API を活用する
  • コンパイル時または実行時に、静的に型やメソッドを加工する

あたりがすぐに思いつく範囲です。前者はアタッチするまでは結構簡単なので、*3あとはプロファイラの作成がどれだけ面倒かってこと。後者はリフレクションと Light-weight コード生成あたりで実行時にやってもいいんですが、実行時に互換性のある型を作るのは制約が多すぎる*4ので IL を加工する方向になってしまいがちなのですが、C# のコードから C# の実コードを生成する T4 を作りこむというのも手かもしれませんね。

*1:id:janus_wel:20101212:1292157491, id:janus_wel:20101214:1292342053

*2:C# の開発現場においてメタデータとして参照されないだろう

*3:自分で自分にアタッチして、メモリ管理まわりなどのランタイムの設定値をちょっと書き換えるぐらいならすぐです

*4:代入互換性を得るためには派生クラスを生成しなければならないので sealed ではダメだったり、メソッド呼び出しに割り込めるのは virtual なものだけ、などなど