2

いくつかの特別なメソッドがあり、コンパイルされたアセンブリで呼び出しを分析したい。

例:

public static class SrcHelper {
    [MySpecialMethod]
    [Conditional( "DEBUG" )]
    public static void ToDo( params object[] info ) {
        /* do nothing */
        /* this method is not called when code is compiled in RELEASE mode */
    }
}
// ... somewhere else in another assembly ...
Array CreateArraySampleMethod( int size ) {
    // This call has only informative character. No functionality is required.
    SrcHelper.ToDo( "Should create array of ", typeof( MyClass ), " with specified size." );
    throw new NotImplementedException();
}

このコンパイルされたコードから、引数の値を取得したい {「指定されたサイズの「、MyClass、」の配列を作成する必要があります。」}。Mono から Cecil を使ってみたところ、"ToDo" メソッドを呼び出すための手順が見つかりました。しかし、引数値で命令を識別する方法がわかりません。

複雑な状況が発生する可能性があり、一部の引数の値を解決できないことはわかっています。しかし、定数値のみを解決する必要があります-私の目的には十分です。

ありがとう。

編集: 「ToDo」メソッド (および同様のもの) は、コメント ( //、/* ... */ ) の代わりに使用する必要があり、コンパイル後に IL を分析し、具体的なアセンブリのドキュメントと todo リストを自動生成する必要があります。 .

4

1 に答える 1

1

コード生成はやや混乱しますが、単純なケースでは実行できます。

コンパイル:

public static void Main(string[] args)
{
    Console.WriteLine("", // ignore this argument
       "Should create array of ", typeof(int), " with specified size." "x");
}

(「x」を追加して、params オーバーロードを強制的に使用させます)

与える

.method public hidebysig static void Main(string[] args) cil managed
{
    .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
    .maxstack 4
    .locals init (
        [0] object[] objArray)
    L_0000: ldstr ""
    L_0005: ldc.i4.4 
    L_0006: newarr object
    L_000b: stloc.0 
    L_000c: ldloc.0 
    L_000d: ldc.i4.0 
    L_000e: ldstr "Should create array of "
    L_0013: stelem.ref 
    L_0014: ldloc.0 
    L_0015: ldc.i4.1 
    L_0016: ldtoken int32
    L_001b: call class [mscorlib]System.Type 
                [mscorlib]System.Type::GetTypeFromHandle(
                    valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0020: stelem.ref 
    L_0021: ldloc.0 
    L_0022: ldc.i4.2 
    L_0023: ldstr " with specified size."
    L_0028: stelem.ref 
    L_0029: ldloc.0 
    L_002a: ldc.i4.3 
    L_002b: ldstr "x"
    L_0030: stelem.ref 
    L_0031: ldloc.0 
    L_0032: call void [mscorlib]System.Console::WriteLine(string, object[])
    L_0037: ret 
}

そのため、il を解析して、コンパイラが生成した配列にプッシュされている引数を検出する必要があります。壊れやすい異端論ですが、次のように言えば十分かもしれません。

  1. 「私のメソッド」への呼び出しを見つけます。
  2. 最も近い以前の newarr オブジェクトを見つける
  3. これらの間にあるすべての ldstr と ldtoken を取り、それらが引数であると想定します。

これは大雑把ですが、ニーズには十分かもしれません。

AOP スタイルのアプローチでは、すべての呼び出しを計測して値をダンプするだけで、実行時に必要なものが得られますが、IL のみが与えられた場合、実際には上記のアプローチが唯一の現実的なオプションになります。

生成されたコードは、リリース ビルドでは大きく異なる場合があります。自動生成された配列と、誰かが明示的に作成した配列を見つけることはできません (呼び出しサイトからさらに離れているか、別のメソッド/コンストラクター/クラスでさえある可能性があります)。

ただし書き

これを行う理由について編集した後、属性ベースの注釈がはるかに優れたソリューションであることに注意してください。直接属性を付けることができるのに、メソッドでこれを行う理由がわかりません...

于 2009-05-13T12:23:51.680 に答える