Microsoft ILでは、値型のメソッドを呼び出すには間接参照が必要です。私たちは「IL」という名前のILGeneratorを持っており、それは現在、我々はそれが価値があるかどうかを確認したい場合は、我々は次のように放出することができ、スタックの一番上のNullableを考えてみましょう:間接的にスタックに値型をロードすることは可能ですか?
var local = il.DeclareLocal(typeof(Nullable<int>));
il.Emit(OpCodes.Stloc, local);
il.Emit(OpCodes.Ldloca, local);
var method = typeof(Nullable<int>).GetMethod("get_HasValue");
il.EmitCall(OpCodes.Call, method, null);
しかし、それは希望ローカル変数として保存スキップして、単純に、何かのようにすでにスタック上の変数のアドレスにメソッドを呼び出すために良いこと:(特にldind_ref)
il.Emit(/* not sure */);
var method = typeof(Nullable<int>).GetMethod("get_HasValue");
il.EmitCall(OpCodes.Call, method, null);
命令のldindファミリーが有望に見えるけどこれが値のボクシングを引き起こすかどうかを知るための十分な文書を見つけることができません。
私はC#コンパイラの出力を見てきましたが、これを実現するためにローカル変数を使用しています。これにより、最初の方法が唯一の方法である可能性があります。誰もが良いアイデアを持っていますか?
****編集:追加の注意事項****コメントアウト行で、以下のプログラムのように、直接メソッドを呼び出そうと
は、動作しません(エラーは、操作ができた「となりますランタイムを不安定にする)。行のコメントを外し、期待どおりに動作し、 "True"を返すことがわかります。それは値型なので(あなたはできるものの、それが参照型である場合)
var m = new DynamicMethod("M", typeof(bool), Type.EmptyTypes);
var il = m.GetILGenerator();
var ctor = typeof(Nullable<int>).GetConstructor(new[] { typeof(int) });
il.Emit(OpCodes.Ldc_I4_6);
il.Emit(OpCodes.Newobj, ctor);
//var local = il.DeclareLocal(typeof(Nullable<int>));
//il.Emit(OpCodes.Stloc, local);
//il.Emit(OpCodes.Ldloca, local);
var getValue = typeof(Nullable<int>).GetMethod("get_HasValue");
il.Emit(OpCodes.Call, getValue);
il.Emit(OpCodes.Ret);
Console.WriteLine(m.Invoke(null, null));
だから、単純にスタック上の値でメソッドを呼び出すことはできません。
私が達成したいのは(あるいは可能かどうかを知るために)、コメントアウトされた3行を置き換えて一時的なローカルを使わずにプログラムを動作させ続けることです。
これも完全に動作しますが、引き続きローカルが必要です。私はこれが、地元の人がいなくてもこれをすることはできないという私の最初の疑惑を確認し始めていると思います。 Stlocは、ローカルに格納されているタイプの追加のメタデータがあるために動作すると思いますが、もう一度呼び出しが行われます。 Odd。 –
ええ、私はそれが期待したようにうまくいかないことが非常に奇妙であることを発見しました。あなたの動的メソッドがNullableを引数として取る場合は、ldarg_0を呼び出すだけで済みますが、メソッドで値の型を実際に作成する必要があると仮定しています。 –
実際、メソッド内で値を作成する必要があります。私が持っている問題は、かなりの数の地方自治体が一時的な操作のために純粋に使用されていることを意味する(異なるタイプの)方法ごとにかなりの数があることです。それは大したことではなく、すべて正常に動作しますが、ちょっと面倒です。 –