I want to replace a method with dynamic method in .Net Framework 4, then I found a very useful answer in Dynamically replace the contents of a C# method?, but I can't get MethodHandle from DynamicMethod directly:
we cannot return a MethodHandle because we cannot track it via GC so this method is off limits
In this article 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;
}
which m_method
can not be found.
Then I noticed m_methodHandle
, but don't know when it will be initialized.
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);
}
According to another question Resolving the tokens found in the IL from a dynamic method, DynamicResolver
has a ResolveToken
method which return methodHandle
address. So I use some code in the answer:
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.");
But... DynamicResolver
will only be initialized in DynamicILGenerator.GetCallableMethod
method which will be called in DynamicMethod.GetMethodDescriptor
method, so the resolver
must be null when I getting it.
Here is my dynamic method:
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;
}
I learned JIT a very little, so I don't quite understand it.
Can someone help?
--------------------------------Edited--------------------------
the answer of @Latency works fine:
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;
}
and after so long I can't remember what's next after get RuntimeMethodHandle and reject a dynamic method, but I hope this can help other people.