【问题标题】:Why does the Mono.Cecil HelloWorld example fail with an exception?为什么 Mono.Cecil HelloWorld 示例失败并出现异常?
【发布时间】:2017-10-13 20:32:17
【问题描述】:
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# 重写了它。当我尝试运行它时,我收到以下错误:

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

这里有什么问题?

【问题讨论】:

    标签: f# mono.cecil


    【解决方案1】:

    我的猜测是问题是由以下行引起的:

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

    在 C# 中,这会将 Main 方法的 IL 处理器分配给 il 变量,但在 F# 中,这只是一个相等性测试,结果为 false - 所以你想要的 IL 代码为Main 生成的方法被添加到构造函数的先前il 处理器中。

    您应该能够使用变量阴影来解决此问题:

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

    【讨论】:

    • 是的,就是这样。虽然与其使用 let 语句,不如将其绑定到 lambda ,否则会发生重复变量错误。另外,我之前已经注意到一次,由于某种原因,F# 没有在相等测试中给我通常的不是单元警告,但我没有想到再次检查相同的错误。谢谢。
    • @MarkoGrdinic 您不会在脚本的顶层收到相等测试警告(您可能想要编写许多表达式并一个一个地运行它们)。如果你的代码在一个函数中,你会得到那些(无论如何这是一个更好的结构)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-01
    • 2014-05-11
    • 1970-01-01
    • 2023-03-22
    相关资源
    最近更新 更多