Pergunta

Here is the definition of my Package class:

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

    member this.Count = info.Length

and here is the IL, I'm trying:

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)

but this doesn't seem to work. I tried:

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

but it just laughs at me. What am I doing wrong?

Foi útil?

Solução

The [<ParamArray>] attribute indicates to a compiler that a method accepts a variable number of arguments. However, the CLR doesn't really support varargs methods -- it's just syntactic sugar provided by the C#/VB.NET/F# compilers.

Now, if you take away the [<ParamArray>], what are you left with?

(info : Object[])

That is the signature of the constructor you're trying to call.

So, you'll need to use the newarr and stelem opcodes to create an array, store the values into it, then call the constructor using the array as the argument. This should do what you want (though I haven't tested it):

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)

NOTE: In this code, I used the dup OpCode to avoid creating a local variable to hold the array reference while storing the element values. This is only feasible because this code is fairly straightforward -- I strongly suggest you create a local variable to hold the array reference if you want to build something more complicated.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top