sir*_*lot 2 reflection f# cil reflection.emit
这是我Package班级的定义:
type Package ([<ParamArray>] info : Object[]) =
do
info |> Array.iter (Console.WriteLine)
member this.Count = info.Length
Run Code Online (Sandbox Code Playgroud)
这是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)
Run Code Online (Sandbox Code Playgroud)
但这似乎不起作用.我试过了:
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<String>; typeof<String>; typeof<String>|]))
Run Code Online (Sandbox Code Playgroud)
以及:
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object>; typeof<Object>; typeof<Object>|]))
Run Code Online (Sandbox Code Playgroud)
但它只是嘲笑我.我究竟做错了什么?
该[<ParamArray>]属性向编译器指示方法接受可变数量的参数.但是,CLR并不真正支持varargs方法 - 它只是C#/ VB.NET/F#编译器提供的语法糖.
现在,如果你带走了[<ParamArray>],你剩下的是什么?
(info : Object[])
Run Code Online (Sandbox Code Playgroud)
这是你试图调用的构造函数的签名.
所以,你需要使用newarr和stelem操作码创建一个数组,值存储到它,然后调用使用数组构造函数的参数.这应该做你想要的(虽然我还没有测试过):
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)
Run Code Online (Sandbox Code Playgroud)
注意:在此代码中,我使用dupOpCode来避免在存储元素值时创建一个局部变量来保存数组引用.这是可行的,因为这段代码相当简单 - 我强烈建议你创建一个局部变量来保存数组引用,如果你想构建更复杂的东西.