私はこれまでのところ運がなく、かなり長い間これを探してきました。ClassFileTransformer
.NETに Java に相当するものはありますか? 基本的に、クラスがロードされるたびに呼び出され、微調整して微調整されたバージョンに置き換えることができるクラスCustomClassFileTransformer
(Java では interface を実装する)を作成したいと考えています。ClassFileTransformer
同様のことを行うフレームワークがあることは知っていますが、独自の を実装するなど、より簡単なものを探していましたClassFileTransformer
。出来ますか?
編集#1。これが必要な理由の詳細:
Ldfld
基本的に、私は C# アプリケーションを持っており、フィールド (操作およびStfld
) に対する読み取りまたは書き込み操作を検出し、読み取り/書き込みが行われる前にいくつかの命令を挿入するために、実行する命令を監視する必要があります。
私はこれを行う方法を知っています (クラスを置き換えるために呼び出される必要がある部分を除く): コードを監視するすべてのメソッドに対して、次のことを行う必要があります。
- メソッドの
MethodBody
使用を取得するMethodBase.GetMethodBody()
- でバイト配列に変換します
MethodBody.GetILAsByteArray()
。返されるbyte[]
には、バイトコードが含まれています。 - hereの説明に従ってバイトコードを分析し、新しい命令を挿入するか、配列の内容を変更して既存の命令を削除/変更する可能性があります。
- 新しいメソッドを作成し、新しいバイトコードを使用してその本体を作成します。
MethodBuilder.CreateMethodBody(byte[] il, int count)
ここil
で、 はバイトコードを含む配列です。これらの微調整されたメソッドをすべて新しいクラスに入れ、新しいクラスを使用して、最初にロードされる予定だったメソッドを置き換えます。
クラスを置き換える代わりに、メソッドが呼び出されるたびに何らかの方法で通知を受けることができます。次に、そのメソッドへの呼び出しを、独自の微調整したメソッドへの呼び出しに置き換えます。これは、最初に呼び出されたときにのみ微調整し、将来の使用のために辞書に入れ、オーバーヘッドを削減します (将来の呼び出しの場合)。メソッドを検索して呼び出すだけで、バイトコードを再度分析する必要はありません)。私は現在これを行う方法を調査しており、LinFuは非常に興味深いように見えますがClassFileTransformer
、クラスを書き直して置き換え、何も監視せずにコードを実行するだけです。
追加の注意: クラスは封印される場合があります。あらゆる種類のクラスを置換できるようにしたいのですが、それらの属性に制限を課すことはできません。
編集#2。実行時にこれを行う必要がある理由。
データへのすべてのアクセスを検出できるように、進行中のすべてを監視する必要があります。これは、ライブラリ クラスのコードにも当てはまります。ただし、どのクラスが使用されるかを事前に知ることはできません。ロードされる可能性のあるすべてのクラスを知っていたとしても、それらが実際に呼び出されるかどうかを確認するのではなく、それらすべてを微調整するとパフォーマンスが大幅に低下します。いいえ。
可能な(しかしかなりハードコアな)解決策。誰かが興味を持っている場合に備えて(そして、質問がお気に入りになっているのを見たので、誰かがそうだと思います)、これが私が今見ているものです。基本的に、プロファイリング API を実装する必要があり、関心のあるイベント (私の場合は JIT コンパイルが開始されるたび) に登録します。ブログ投稿の抜粋:
- ICorProfilerCallback2::ModuleLoadFinished コールバックで、ICorProfilerInfo2::GetModuleMetadata を呼び出して、そのモジュールのメタデータ インターフェイスへのポインターを取得します。
- 必要なメタデータ インターフェイスの QI。MSDN で「IMetaDataImport」を検索し、目次を調べてメタデータ インターフェイスに関するトピックを見つけます。
- メタデータの世界に入ると、フィールドや関数プロトタイプを含む、モジュール内のすべての型にアクセスできます。メタデータの署名を解析する必要がある場合は、この署名パーサーが役立つ場合があります。
- ICorProfilerCallback2::JITCompilationStarted コールバックでは、ICorProfilerInfo2::GetILFunctionBody を使用して元の IL を調べ、ICorProfilerInfo2::GetILFunctionBodyAllocator を使用してから ICorProfilerInfo2::SetILFunctionBody を使用してその IL を独自のものに置き換えることができます。
すばらしいニュース: JIT コンパイルが開始されると通知が届き、クラスの置き換えなどを心配することなく、その場でバイトコードを置き換えることができます。あまりすばらしいニュースではありません: API のコールバック メソッドからマネージ コードを呼び出すことはできません。 、これは理にかなっていますが、Cecilを使用できるのとは対照的に、ILコードなどを自分で解析していることを意味します。
AOP フレームワーク ( PostSharpなど) を使用せずにこれを行う簡単な方法はないと思います。誰かが他のアイデアを持っている場合は、私に知らせてください。質問にまだ回答済みのマークを付けていません。