【问题标题】:How do you emit to class that has a 'params' constructor?您如何向具有“参数”构造函数的类发出?
【发布时间】:2013-03-20 01:30:08
【问题描述】:

这是我的Package 类的定义:

type Package ([<ParamArray>] info : Object[]) =
    do
        info |> Array.iter (Console.WriteLine)

    member this.Count = info.Length

这是 IL,我正在尝试:

let ilGen = methodbuild.GetILGenerator()

ilGen.Emit(OpCodes.Ldstr, "This is 1")
ilGen.Emit(OpCodes.Ldstr, "Two")
ilGen.Emit(OpCodes.Ldstr, "Three")
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object[]>|]))
ilGen.Emit(OpCodes.Ret)

但这似乎不起作用。我试过了:

ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<String>; typeof<String>; typeof<String>|]))

一口井:

ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object>; typeof<Object>; typeof<Object>|]))

但它只是在嘲笑我。我做错了什么?

【问题讨论】:

    标签: reflection f# cil reflection.emit


    【解决方案1】:

    [&lt;ParamArray&gt;] 属性向编译器指示方法接受可变数量的参数。但是,CLR 并不真正支持 varargs 方法——它只是 C#/VB.NET/F# 编译器提供的语法糖。

    现在,如果你拿走[&lt;ParamArray&gt;],你还剩下什么?

    (info : Object[])
    

    这是您尝试调用的构造函数的签名。

    因此,您需要使用newarrstelem 操作码创建一个数组,将值存储到其中,然后使用该数组作为 参数调用构造函数。这应该做你想做的(虽然我没有测试过):

    let ilGen = methodbuild.GetILGenerator()
    
    // Create the array
    ilGen.Emit(OpCodes.Ldc_I4_3)
    ilGen.Emit(OpCodes.Newarr, typeof<obj>)
    
    // Store the first array element
    ilGen.Emit(OpCodes.Dup)
    ilGen.Emit(OpCodes.Ldc_I4_0)
    ilGen.Emit(OpCodes.Ldstr, "This is 1")
    ilGen.Emit(OpCodes.Stelem_Ref)
    
    // Store the second array element
    ilGen.Emit(OpCodes.Dup)
    ilGen.Emit(OpCodes.Ldc_I4_1)
    ilGen.Emit(OpCodes.Ldstr, "Two")
    ilGen.Emit(OpCodes.Stelem_Ref)
    
    // Store the third array element
    ilGen.Emit(OpCodes.Dup)
    ilGen.Emit(OpCodes.Ldc_I4_2)
    ilGen.Emit(OpCodes.Ldstr, "Three")
    ilGen.Emit(OpCodes.Stelem_Ref)
    
    // Call the constructor
    ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object[]>|]))
    ilGen.Emit(OpCodes.Ret)
    

    注意:在这段代码中,我使用了dup OpCode 来避免在存储元素值时创建一个局部变量来保存数组引用。这只是可行的,因为这段代码相当简单——如果你想构建更复杂的东西,我强烈建议你创建一个局部变量来保存数组引用。

    【讨论】:

    • 顺便说一句,CLR(和 C#)确实支持 varargs,除了它只是为了与本机可变参数方法进行互操作,它很尴尬,没有人使用它。
    • @svick 是的,这是真的。我的观点是托管方法只有一个调用约定,它不支持varargs。在托管方法中或在托管方法中使用varargs 只是围绕托管调用约定的语法糖。
    • 做到了,太棒了。谢谢先生!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 2018-02-25
    • 1970-01-01
    • 2016-05-22
    • 2016-10-17
    • 2018-04-08
    相关资源
    最近更新 更多