首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C#如何从DynamicMethod获取RuntimeMethodHandle?

C#如何从DynamicMethod获取RuntimeMethodHandle?
EN

Stack Overflow用户
提问于 2017-08-31 11:02:47
回答 1查看 2K关注 0票数 0

我想在.Net Framework4中用动态方法替换一个方法,然后我在Dynamically replace the contents of a C# method?中找到了一个非常有用的答案,但我不能直接从DynamicMethod获得MethodHandle:

我们不能返回MethodHandle,因为我们不能通过GC跟踪它,所以此方法是禁止的

在本文CLR Injection: Runtime Method Replacer中,

代码语言:javascript
复制
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,但不知道它什么时候会初始化。

代码语言:javascript
复制
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 methodDynamicResolver有一个返回methodHandle地址的ResolveToken方法。因此,我在答案中使用了一些代码:

代码语言:javascript
复制
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必须为空。

下面是我的动态方法:

代码语言:javascript
复制
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的答案很好用:

代码语言:javascript
复制
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和拒绝动态方法之后会发生什么了,但我希望这能对其他人有所帮助。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-07-06 15:12:01

lol @ lock(this)

.NET框架在v3.5之后更改了其内存规格

您将需要设置条件,以针对框架版本进行测试。

通常,您可能希望通过执行以下操作重载该方法:

代码语言:javascript
复制
private static RuntimeMethodHandle GetDynamicMethodRuntimeHandle(DynamicMethod method) => method.MethodHandle;

但是,动态方法不支持此操作。

获取基本定义似乎是可行的。

代码语言:javascript
复制
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;
}

它可以简化为:

代码语言:javascript
复制
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;
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45972562

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档