2

これが私の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>|]))

しかし、それは私を笑うだけです。私は何を間違っていますか?

4

1 に答える 1

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を使用しました。このコードはかなり単純なので、これは実行可能です。より複雑なものを作成する場合は、配列参照を保持するローカル変数を作成することを強くお勧めします。

于 2013-03-20T02:24:04.043 に答える