MSIL store a value of structure to return

490 views Asked by At

I am using RemotingLite library (see at github) and have an issue with Proxy class factory. In few words the issue is when generating code for return an ValueType objects like user defined structures.

Here a part of original code:

...
mIL.Emit(OpCodes.Ldloc, resultLB.LocalIndex); //load the result array
mIL.Emit(OpCodes.Ldc_I4, 0); //load the index of the return value. Alway 0
mIL.Emit(OpCodes.Ldelem_Ref); //load the value in the index of the array

if (returnType.IsValueType)
{
    mIL.Emit(OpCodes.Unbox, returnType); //unbox it
    mIL.Emit(ldindOpCodeTypeMap[returnType]);
}
else
    mIL.Emit(OpCodes.Castclass, returnType);
}
        mIL.Emit(OpCodes.Ret);

ldindOpCodeTypeMap is a dictionary with opcodes like OpCodes.Ldind_U2 etc. So it works only for standard MSIL types like Int16, Int32 etc. But what I need to do if I need to push to stack then return a custom ValueType value (for example - Guid - size is 16 bytes)?

For example:

...
mIL.Emit(OpCodes.Unbox, returnType); //unbox it
OpCode opcode;
if (ldindOpCodeTypeMap.TryGetValue(returnType, out opcode))
{
    mIL.Emit(ldindOpCodeTypeMap[returnType]);
}
else
{
    // here I getting the size of custom type
    var size = System.Runtime.InteropServices.Marshal.SizeOf(returnType);
    // what next?
}
...

Here I have get a size of custom ValueType value. So how Load a value of custom ValueType onto the evaluation stack indirectly like Ldind_x opcodes do that? Thanks!

1

There are 1 answers

0
user12864 On BEST ANSWER

Ldobj will do what you want. But you could also replace the entire conditional with Unbox_Any: it will do everything you need for a value type or a reference type.

The full replacement for your posted code would be:

...
mIL.Emit(OpCodes.Ldloc, resultLB.LocalIndex); //load the result array
mIL.Emit(OpCodes.Ldc_I4, 0); //load the index of the return value. Alway 0
mIL.Emit(OpCodes.Ldelem_Ref); //load the value in the index of the array

mIL.Emit(OpCodes.Unbox_Any, returnType);
mIL.Emit(OpCodes.Ret);