C# ILGenerator在int上发出GetHashCode调用
当我运行此代码时:C# ILGenerator在int上发出GetHashCode调用,c#,.net-core,C#,.net Core,当我运行此代码时: 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.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
如何发出正确的调用?GetHashCode()是一个实例方法,因此需要在“引用”上调用它。虽然您不需要框装整数,但需要推送到堆栈上的这个
参数不是整数值本身,而是指向整数值的指针
因此,您需要一个局部变量,可以在其中存储整数值,然后将指向该局部值的指针推送到堆栈上(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}");
}
static void Main(字符串[]args)
{
var方法=新的DynamicMethod(“Get17HashCode”,typeof(int),new Type[0],typeof(Program).Module);
var ilGenerator=method.GetILGenerator();
ilGenerator.DeclareLocal(type of(int));
ilGenerator.Emit(操作码.Ldc_I4_S,17);
ilGenerator.Emit(操作码.Stloc_0);
ilGenerator.Emit(操作码.Ldloca_S,0);
Emit(opcode.Call,typeof(int).GetMethod(nameof(int.GetHashCode));
ilGenerator.Emit(操作码.Ret);
var delegateFunction=(Func)method.CreateDelegate(typeof(Func));
var result=delegateFunction();
WriteLine($“Got{result}”);
}
您得到
NullReferenceException
的原因可能是因为地址17
仍在CLR为其注册空引用处理程序的地址0
处注册的虚拟内存页中。较大的值应导致AccessViolationException:尝试读取或写入受保护的内存
(假设堆栈上有一个简短的表示)。先用C#编写代码,然后使用像ildasm.exe这样的反编译器查看它使用的操作码。它的工作方式与您想象的不同,简单的值类型经过了大量优化以避免装箱。您需要存储在本地,然后从该本地重新加载。某种形式的stloc/ldloc。试试看sharplab@pinkfloydx33需要本地,以便将指向该本地的地址作为指针推送到堆栈上(ldloca.s
),不是值本身。为什么在已装箱的实例上调用该方法不起作用?那么您需要对对象的GetHashCode
执行虚拟方法调用:ilGenerator.Emit(opcode.Callvirt,typeof(object.GetHashCode))代码>