你如何向具有'params'构造函数的类发出声音?

时间:2013-03-20 01:30:08

标签: reflection f# cil reflection.emit

以下是我的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>|]))

a well as:

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

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

1 个答案:

答案 0 :(得分:5)

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

现在,如果你带走了[<ParamArray>],你剩下的是什么?

(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来避免在存储元素值时创建一个局部变量来保存数组引用。这是可行的,因为这段代码相当简单 - 我强烈建议你创建一个局部变量来保存数组引用,如果你想构建更复杂的东西。