MSIL存储结构值以返回

时间:2015-06-21 17:23:57

标签: c# .net cil il

我正在使用RemotingLite库(see at github)并且在Proxy类工厂中存在问题。 简而言之,问题在于生成用于返回ValueType对象(如用户定义的结构)的代码。

这是原始代码的一部分:

...
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是一个包含OpCodes.Ldind_U2等操作码的字典。所以它只适用于标准的MSIL类型,如Int16, Int32等。但是如果我需要推送到堆栈,我需要做什么然后返回自定义ValueType值(例如 - Guid - 大小为16个字节)?

例如:

...
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?
}
...

此处我获得了自定义ValueType值的大小。那么如何像ValueType x操作码那样间接地将自定义Ldind_的值加载到评估堆栈中呢? 谢谢!

1 个答案:

答案 0 :(得分:3)

Ldobj会做你想要的。但是你也可以用Unbox_Any替换整个条件:它将完成你对值类型或引用类型所需的一切。

您发布的代码的完全替换将是:

...
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);