2

私は実際にはコーディング時間の 95% を F# の FSI に費やしているように見えるので、迂回して (「気が散る」を参照)、いくつかのユーティリティ関数を書きたいと思いました。

私が興味を持っている特定のユーティリティは、特定の関数の IL をダンプできる「逆アセンブル」(http://www.cons.org/cmucl/doc/reading-disassembly.html) 関数です。基本的な静的分析など、一般的にこれは気晴らしの天国です。byteArrayIL を MSIL 名に (ほぼ) マップするコードは既に作成しています。

以下は、現在のモジュールから関数名を取得するために使用されるスニペットです。

let dec_c = MethodBase.GetCurrentMethod().DeclaringType

System.Reflection.Assembly.GetAssembly(dec_c).GetTypes() 
|> Seq.map (fun x -> x.FullName) //, get_function_instructions x)

x.FullName は実際の関数名を反映しているため、これはほとんど問題なく機能します。

FSI_0001
<StartupCode$FSI_0001>.$FSI_0001
FSI_0002
FSI_0002+instructions_of_bytes@24
FSI_0002+remove_null_function_body_bytes@32
FSI_0002+remove_null_function_body_bytes@31-1
FSI_0002+resolve_IL_from_bytes@38
FSI_0002+resolve_IL_from_bytes@36-1
FSI_0002+it@49
FSI_0002+it@50-1
<StartupCode$FSI_0002>.$FSI_0002
FSI_0003
FSI_0003+it@49-2
FSI_0003+it@50-3
<StartupCode$FSI_0003>.$FSI_0003

したがって、関数名に基づいてフィルター処理する関数を簡単に作成できます。

残念ながら (そしておそらく私の誤解による)、すべての関数がこの方法で利用できるわけではないようです。たとえば、次の単純な関数を定義してからダンプを再実行すると、次のようになります。

(* reload FSI *)
let simple_add x = x + 1
(* rerun the function name dumping *)

FSI_0001
<StartupCode$FSI_0001>.$FSI_0001
FSI_0002
FSI_0002+instructions_of_bytes@24
FSI_0002+remove_null_function_body_bytes@32
FSI_0002+remove_null_function_body_bytes@31-1
FSI_0002+resolve_IL_from_bytes@38
FSI_0002+resolve_IL_from_bytes@36-1
FSI_0002+it@50
FSI_0002+it@51-1
<StartupCode$FSI_0002>.$FSI_0002

奇妙なことに、結果のテキストに「simple_add」関数が存在しません。

考え: 1. 関数 simple_add は、使用されていることがわかるまでリフレクションによって認識されないのではないでしょうか? 奇妙に聞こえます。2. これらの「FSI_0002+it」文字列の 1 つが実際に関数である可能性があります。

質問: 1. 出力にすべての関数名が反映されないのはなぜですか? 2.これを行うためのより良い方法はありますか?

4

1 に答える 1

3

私は答えで寝た(半分寝た)と思います、私はそれについて間違っていました、関数ごとの文字列名のリストを持つ必要はありません...

let get_function_instructions (mb : System.Type) = 
  mb.GetMethods() 
  |> Seq.map ...

let find_func_print_instructions f =
  f.GetType()
  |> get_function_instructions 
  |> print_instruction_text
于 2012-11-21T19:27:12.680 に答える