当我运行此代码时:
var il = getHashCode.GetILGenerator();
il.Emit(OpCodes.Ldc_I4_S, 17); // put "17" on the stack
il.Emit(OpCodes.Call, typeof(Int32).GetMethod("GetHashCode", new Type[] { }));
il.Emit(OpCodes.Ret);
我正在获取System.NullReferenceException:对象引用未设置为对象的实例。
当我输入值时:
var il = getHashCode.GetILGenerator();
il.Emit(OpCodes.Ldc_I4_S, 17); // put "17" on the stack
il.Emit(OpCodes.Box, typeof(Int32));
il.Emit(OpCodes.Call, typeof(Int32).GetMethod("GetHashCode", new Type[] { }));
il.Emit(OpCodes.Ret);
返回值为-1875039000,但应为17。
如何发出正确的电话?
答案 0 :(得分:2)
GetHashCode()
是一个实例方法,因此您需要在“引用”上调用它。虽然不需要装箱整数,但需要压入堆栈的this
参数不是整数值本身,而是指向整数值的指针。
由于这个原因,您需要一个局部变量,可以在其中存储整数值,然后将指向该局部值的指针推入堆栈(ldloca.s
)并调用实例方法:
static void Main(string[] args)
{
var method = new DynamicMethod("Get17HashCode", typeof(int), new Type[0], typeof(Program).Module);
var ilGenerator = method.GetILGenerator();
ilGenerator.DeclareLocal(typeof(int));
ilGenerator.Emit(OpCodes.Ldc_I4_S, 17);
ilGenerator.Emit(OpCodes.Stloc_0);
ilGenerator.Emit(OpCodes.Ldloca_S, 0);
ilGenerator.Emit(OpCodes.Call, typeof(int).GetMethod(nameof(int.GetHashCode)));
ilGenerator.Emit(OpCodes.Ret);
var delegateFunction = (Func<int>)method.CreateDelegate(typeof(Func<int>));
var result = delegateFunction();
Console.WriteLine($"Got {result}");
}
获得NullReferenceException
的原因可能是因为地址17
仍在CLR为空引用注册处理程序的地址0
上注册的虚拟内存页中。较大的值应导致AccessViolationException: Attempted to read or write protected memory
(假设堆栈上使用简短形式表示)。