2017-10-13 5 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 

Ich habe the example aus der Antwort auf diese Frage ausgeliehen und neu in F # geschrieben. Wenn ich versuche, es auszuführen, erhalte ich den folgenden Fehler:Warum schlägt das Mono.Cecil HelloWorld-Beispiel mit einer Ausnahme fehl?

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). 

Was ist hier falsch?

Antwort

2

Meine Vermutung ist, dass das Problem durch die folgende Zeile verursacht wird:

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

In C#, dies den IL-Prozessor für die Main Verfahren zum il Variablen zuweisen würde, aber in F #, dies ist nur ein Gleichheitstest, der in false resultiert - und so der IL-Code, den Sie für die Main-Methode generieren wollten, wird dem vorherigen il-Prozessor für den Konstruktor hinzugefügt.

sollten Sie in der Lage sein, diese mit variabler Abschattung zu beheben:

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

Ja, das war es. Anstatt eine let-Anweisung zu verwenden, wäre es besser, sie an ein Lambda zu binden, da andernfalls der doppelte Variablenfehler auftritt. Außerdem habe ich schon einmal bemerkt, dass F # mir aus irgendeinem Grund nicht die übliche Einheitswarnung auf dem Gleichheitstest gibt, aber es kam mir nicht in den Sinn, nochmal nach dem gleichen Fehler zu suchen. Vielen Dank. –

+1

@MarkoGrdinic Sie erhalten die Gleichheitstestwarnung nicht auf oberster Ebene in einem Skript (wo Sie vielleicht eine Anzahl von Ausdrücken schreiben und sie nacheinander ausführen möchten). Sie würden diese bekommen, wenn Ihr Code innerhalb einer Funktion wäre (was sowieso eine bessere Struktur ist) –

Verwandte Themen