2017-10-13 12 views
1
open System 
open Mono.Cecil 
open Mono.Cecil.Cil 

let myHelloWorldApp = 
    AssemblyDefinition.CreateAssembly(
     new AssemblyNameDefinition("HelloWorld", new Version(1, 0, 0, 0)), "HelloWorld", ModuleKind.Console) 

let module_ = myHelloWorldApp.MainModule 

// create the program type and add it to the module 
let programType = 
    new TypeDefinition("HelloWorld", "Program", 
     Mono.Cecil.TypeAttributes.Class ||| Mono.Cecil.TypeAttributes.Public, module_.TypeSystem.Object) 

module_.Types.Add(programType) 

// add an empty constructor 
let ctor = 
    new MethodDefinition(".ctor", Mono.Cecil.MethodAttributes.Public ||| Mono.Cecil.MethodAttributes.HideBySig 
     ||| Mono.Cecil.MethodAttributes.SpecialName ||| Mono.Cecil.MethodAttributes.RTSpecialName, module_.TypeSystem.Void) 

// create the constructor's method body 
let il = ctor.Body.GetILProcessor() 

il.Append(il.Create(OpCodes.Ldarg_0)) 

// call the base constructor 
il.Append(il.Create(OpCodes.Call, module_.ImportReference(typeof<obj>.GetConstructor([||])))) 

il.Append(il.Create(OpCodes.Nop)) 
il.Append(il.Create(OpCodes.Ret)) 

programType.Methods.Add(ctor) 

// define the 'Main' method and add it to 'Program' 
let mainMethod = 
    new MethodDefinition("Main", 
     Mono.Cecil.MethodAttributes.Public ||| Mono.Cecil.MethodAttributes.Static, module_.TypeSystem.Void) 

programType.Methods.Add(mainMethod) 

// add the 'args' parameter 
let argsParameter = 
    new ParameterDefinition("args", 
     Mono.Cecil.ParameterAttributes.None, module_.ImportReference(typeof<string[]>)) 

mainMethod.Parameters.Add(argsParameter); 

// create the method body 
il = mainMethod.Body.GetILProcessor() 

il.Append(il.Create(OpCodes.Nop)) 
il.Append(il.Create(OpCodes.Ldstr, "Hello World")) 

let writeLineMethod = 
    il.Create(OpCodes.Call, 
     module_.ImportReference(typeof<Console>.GetMethod("WriteLine", [|typeof<string>|]))) 

// call the method 
il.Append(writeLineMethod) 

il.Append(il.Create(OpCodes.Nop)) 
il.Append(il.Create(OpCodes.Ret)) 

// set the entry point and save the module 
myHelloWorldApp.EntryPoint <- mainMethod 

私はその質問の答えからthe exampleを借りて、F#で書き直しました。実行しようとすると、次のエラーが表示されます。Mono.Cecil HelloWorldの例が例外で失敗するのはなぜですか?

Unhandled Exception: System.TypeLoadException: Could not load type 'HelloWorld.Program' from assembly 'Hello 
on=1.0.0.0, Culture=neutral, PublicKeyToken=null' because the method 'Main' has no implementation (no RVA). 

ここで何が間違っていますか?

答えて

2

私の推測では、問題は次の行によって引き起こされていることである:C#では

// create the method body 
il = mainMethod.Body.GetILProcessor() 

、これはil変数にMain方法のためのILプロセッサを割り当てますが、F#で、これはただのです結果はfalseとなります。したがって、Mainメソッドに対して生成するILコードは、コンストラクタの前のilプロセッサに追加されます。

あなたは変数シャドウイングを使用してこの問題を解決することができるはずです。

// create the method body 
let il = mainMethod.Body.GetILProcessor() 
+0

うん、これはそれでした。 let文を使うのではなく、ラムダにバインドする方が良いでしょう。さもなければ、重複する変数エラーが発生します。また、私はすでに何らかの理由でその前に気付いていましたが、F#は私に平等テストのユニット警告ではありませんが、同じエラーを再度確認することはありませんでした。ありがとう。 –

+1

@MarkoGrdinicスクリプト内のトップレベルの平等テスト警告(多数の式を書いて1つずつ実行したい場合があります)がありません。あなたのコードが関数の中にあった場合は、それらを取得します(これは、とにかく優れた構造です) –

関連する問題