In Microsoft IL, to call a method on a value type you need an indirect reference. Lets say we have an ILGenerator named "il" and that currently we have a Nullable on top of the stack, if we want to check whether it has a value then we could emit the following:
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);
However it would be nice to skip saving it as a local variable, and simply call the method on the address of the variable already on the stack, something like:
il.Emit(/* not sure */);
var method = typeof(Nullable<int>).GetMethod("get_HasValue");
il.EmitCall(OpCodes.Call, method, null);
The ldind family of instructions looks promising (particularly ldind_ref) but I can't find sufficient documentation to know whether this would cause boxing of the value, which I suspect it might.
I've had a look at the C# compiler output, but it uses local variables to achieve this, which makes me believe the first way may be the only way. Anyone have any better ideas?
**** Edit: Additional Notes ****
Attempting to call the method directly, as in the following program with the lines commented out, doesn't work (the error will be "Operation could destabilise the runtime"). Uncomment the lines and you'll see that it does work as expected, returning "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));
So you can't simply call the method with the value on the stack because it's a value type (though you could if it was a reference type).
What I'd like to achieve (or to know whether it is possible) is to replace the three lines that are shown commented out, but keep the program working, without using a temporary local.