C# 如何从 DynamicMethod 获取 RuntimeMethodHandle?
C# how to get RuntimeMethodHandle from DynamicMethod?
我想用 .Net Framework 4 中的动态方法替换方法,然后我在 Dynamically replace the contents of a C# method? 中找到了一个非常有用的答案,但我无法直接从 DynamicMethod 获取 MethodHandle:
we cannot return a MethodHandle because we cannot track it via GC so this method is off limits
在本文中CLR Injection: Runtime Method Replacer、
private static IntPtr GetDynamicMethodRuntimeHandle(MethodBase method)
{
if (method is DynamicMethod)
{
FieldInfo fieldInfo = typeof(DynamicMethod).GetField("m_method",
BindingFlags.NonPublic|BindingFlags.Instance);
return ((RuntimeMethodHandle)fieldInfo.GetValue(method)).Value;
}
return method.MethodHandle.Value;
}
找不到m_method
。
然后注意到了m_methodHandle
,但是不知道什么时候会初始化
internal unsafe RuntimeMethodHandle GetMethodDescriptor() {
if (m_methodHandle == null) {
lock (this) {
if (m_methodHandle == null) {
if (m_DynamicILInfo != null)
m_DynamicILInfo.GetCallableMethod(m_module, this);
else {
if (m_ilGenerator == null || m_ilGenerator.ILOffset == 0)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_BadEmptyMethodBody", Name));
m_ilGenerator.GetCallableMethod(m_module, this);
}
}
}
}
return new RuntimeMethodHandle(m_methodHandle);
}
根据另一个问题Resolving the tokens found in the IL from a dynamic method,DynamicResolver
有一个ResolveToken
方法return methodHandle
地址。所以我在答案中使用了一些代码:
var resolver = typeof(DynamicMethod)
.GetField("m_resolver", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(dynamicMethod);
if (resolver == null)
throw new ArgumentException("The dynamic method's IL has not been finalized.");
但是... DynamicResolver
只会在 DynamicILGenerator.GetCallableMethod
方法中初始化,该方法将在 DynamicMethod.GetMethodDescriptor
方法中调用,所以当我得到时 resolver
必须为空它。
这是我的动态方法:
private static MethodInfo build(MethodInfo originMethod)
{
var parameters = originMethod.GetParameters();
var parameterTypes = parameters.Length == 0 ?
null :
parameters
.Select(param => param.ParameterType)
.ToArray();
DynamicMethod method = new DynamicMethod(
originMethod.Name,
originMethod.ReturnType,
parameterTypes,
originMethod.Module);
ILGenerator il = method.GetILGenerator();
il.Emit(OpCodes.Ldstr, "Injected");
var console_writeline = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
il.Emit(OpCodes.Call, console_writeline);
il.Emit(OpCodes.Ret);
return method;
}
我学的JIT很少,不是很懂。
有人可以帮忙吗?
--------------------------------已编辑------------ --------------
@Latency 的回答很好:
RuntimeMethodHandle GetMethodRuntimeHandle(MethodBase method)
{
if (!(method is DynamicMethod))
return method.MethodHandle;
RuntimeMethodHandle handle;
if (Environment.Version.Major == 4)
{
var getMethodDescriptorInfo = typeof(DynamicMethod).GetMethod("GetMethodDescriptor", BindingFlags.NonPublic | BindingFlags.Instance);
handle = (RuntimeMethodHandle)getMethodDescriptorInfo.Invoke(method, null);
}
else
{
var fieldInfo = typeof(DynamicMethod).GetField("m_method", BindingFlags.NonPublic | BindingFlags.Instance);
handle = (RuntimeMethodHandle)fieldInfo.GetValue(method);
}
return handle;
}
过了这么久我不记得获取 RuntimeMethodHandle 并拒绝动态方法之后的下一步是什么,但我希望这可以帮助其他人。
哈哈@lock(this)
.NET Framework 在 v3.5 之后更改了内存规格
您需要输入条件以针对框架版本进行测试。
通常,您希望通过执行以下操作来重载该方法:
private static RuntimeMethodHandle GetDynamicMethodRuntimeHandle(DynamicMethod method) => method.MethodHandle;
但是,动态方法不支持此操作。
获取基本定义似乎有效。
GetDynamicMethodRuntimeHandle(DynamicMethod method) => GetDynamicMethodRuntimeHandle(method.GetBaseDefinition());
private static RuntimeMethodHandle GetDynamicMethodRuntimeHandle(MethodBase method) {
RuntimeMethodHandle handle;
if (Environment.Version.Major == 4) {
var getMethodDescriptorInfo = typeof(DynamicMethod).GetMethod("GetMethodDescriptor", BindingFlags.NonPublic | BindingFlags.Instance);
handle = (RuntimeMethodHandle) getMethodDescriptorInfo.Invoke(method, null);
} else {
var fieldInfo = typeof(DynamicMethod).GetField("m_method", BindingFlags.NonPublic | BindingFlags.Instance);
handle = (RuntimeMethodHandle) fieldInfo.GetValue(method);
}
return handle;
}
可以简化为:
private static IntPtr GetDynamicMethodRuntimeHandle(MethodBase method) {
if (!(method is DynamicMethod))
return method.MethodHandle.Value;
var fieldInfo = typeof(DynamicMethod).GetField("m_method", BindingFlags.NonPublic | BindingFlags.Instance);
return fieldInfo != null ? ((RuntimeMethodHandle) fieldInfo.GetValue(method)).Value : method.MethodHandle.Value;
}
我想用 .Net Framework 4 中的动态方法替换方法,然后我在 Dynamically replace the contents of a C# method? 中找到了一个非常有用的答案,但我无法直接从 DynamicMethod 获取 MethodHandle:
we cannot return a MethodHandle because we cannot track it via GC so this method is off limits
在本文中CLR Injection: Runtime Method Replacer、
private static IntPtr GetDynamicMethodRuntimeHandle(MethodBase method)
{
if (method is DynamicMethod)
{
FieldInfo fieldInfo = typeof(DynamicMethod).GetField("m_method",
BindingFlags.NonPublic|BindingFlags.Instance);
return ((RuntimeMethodHandle)fieldInfo.GetValue(method)).Value;
}
return method.MethodHandle.Value;
}
找不到m_method
。
然后注意到了m_methodHandle
,但是不知道什么时候会初始化
internal unsafe RuntimeMethodHandle GetMethodDescriptor() {
if (m_methodHandle == null) {
lock (this) {
if (m_methodHandle == null) {
if (m_DynamicILInfo != null)
m_DynamicILInfo.GetCallableMethod(m_module, this);
else {
if (m_ilGenerator == null || m_ilGenerator.ILOffset == 0)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_BadEmptyMethodBody", Name));
m_ilGenerator.GetCallableMethod(m_module, this);
}
}
}
}
return new RuntimeMethodHandle(m_methodHandle);
}
根据另一个问题Resolving the tokens found in the IL from a dynamic method,DynamicResolver
有一个ResolveToken
方法return methodHandle
地址。所以我在答案中使用了一些代码:
var resolver = typeof(DynamicMethod)
.GetField("m_resolver", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(dynamicMethod);
if (resolver == null)
throw new ArgumentException("The dynamic method's IL has not been finalized.");
但是... DynamicResolver
只会在 DynamicILGenerator.GetCallableMethod
方法中初始化,该方法将在 DynamicMethod.GetMethodDescriptor
方法中调用,所以当我得到时 resolver
必须为空它。
这是我的动态方法:
private static MethodInfo build(MethodInfo originMethod)
{
var parameters = originMethod.GetParameters();
var parameterTypes = parameters.Length == 0 ?
null :
parameters
.Select(param => param.ParameterType)
.ToArray();
DynamicMethod method = new DynamicMethod(
originMethod.Name,
originMethod.ReturnType,
parameterTypes,
originMethod.Module);
ILGenerator il = method.GetILGenerator();
il.Emit(OpCodes.Ldstr, "Injected");
var console_writeline = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
il.Emit(OpCodes.Call, console_writeline);
il.Emit(OpCodes.Ret);
return method;
}
我学的JIT很少,不是很懂。
有人可以帮忙吗?
--------------------------------已编辑------------ --------------
@Latency 的回答很好:
RuntimeMethodHandle GetMethodRuntimeHandle(MethodBase method)
{
if (!(method is DynamicMethod))
return method.MethodHandle;
RuntimeMethodHandle handle;
if (Environment.Version.Major == 4)
{
var getMethodDescriptorInfo = typeof(DynamicMethod).GetMethod("GetMethodDescriptor", BindingFlags.NonPublic | BindingFlags.Instance);
handle = (RuntimeMethodHandle)getMethodDescriptorInfo.Invoke(method, null);
}
else
{
var fieldInfo = typeof(DynamicMethod).GetField("m_method", BindingFlags.NonPublic | BindingFlags.Instance);
handle = (RuntimeMethodHandle)fieldInfo.GetValue(method);
}
return handle;
}
过了这么久我不记得获取 RuntimeMethodHandle 并拒绝动态方法之后的下一步是什么,但我希望这可以帮助其他人。
哈哈@lock(this)
.NET Framework 在 v3.5 之后更改了内存规格
您需要输入条件以针对框架版本进行测试。
通常,您希望通过执行以下操作来重载该方法:
private static RuntimeMethodHandle GetDynamicMethodRuntimeHandle(DynamicMethod method) => method.MethodHandle;
但是,动态方法不支持此操作。
获取基本定义似乎有效。
GetDynamicMethodRuntimeHandle(DynamicMethod method) => GetDynamicMethodRuntimeHandle(method.GetBaseDefinition());
private static RuntimeMethodHandle GetDynamicMethodRuntimeHandle(MethodBase method) {
RuntimeMethodHandle handle;
if (Environment.Version.Major == 4) {
var getMethodDescriptorInfo = typeof(DynamicMethod).GetMethod("GetMethodDescriptor", BindingFlags.NonPublic | BindingFlags.Instance);
handle = (RuntimeMethodHandle) getMethodDescriptorInfo.Invoke(method, null);
} else {
var fieldInfo = typeof(DynamicMethod).GetField("m_method", BindingFlags.NonPublic | BindingFlags.Instance);
handle = (RuntimeMethodHandle) fieldInfo.GetValue(method);
}
return handle;
}
可以简化为:
private static IntPtr GetDynamicMethodRuntimeHandle(MethodBase method) {
if (!(method is DynamicMethod))
return method.MethodHandle.Value;
var fieldInfo = typeof(DynamicMethod).GetField("m_method", BindingFlags.NonPublic | BindingFlags.Instance);
return fieldInfo != null ? ((RuntimeMethodHandle) fieldInfo.GetValue(method)).Value : method.MethodHandle.Value;
}