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);
ただし、それをローカル変数として保存することをスキップして、次のように、既にスタックにある変数のアドレスでメソッドを呼び出すだけでよいでしょう。
il.Emit(/* not sure */);
var method = typeof(Nullable<int>).GetMethod("get_HasValue");
il.EmitCall(OpCodes.Call, method, null);
命令の ldind ファミリ (特に ldind_ref) は有望に見えますが、これが値のボックス化を引き起こすかどうかを知るための十分なドキュメントが見つかりません。
私は 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 行を置き換えることですが、一時的なローカルを使用せずにプログラムを動作させ続けることです。