我正在玩 DynamicMethod 并旨在执行以下操作:
我有一个动作,我从中获取 IL 代码作为字节使用GetILAsByteArray()
. 从这个字节我想创建一个动态方法并执行。这是我正在尝试做的一个例子:
class Program
{
static void Main(string[] args)
{
//Create action and execute
Action<string> myAction = s =>
{
Console.WriteLine("Hello " + s);
};
myAction("World");
//Get IL bytes
byte[] ilBytes = myAction.GetMethodInfo().GetMethodBody().GetILAsByteArray();
DynamicMethod dynamicCallback = new DynamicMethod("myAction", typeof(void), new Type[] { typeof(string) });
DynamicILInfo dynamicIlInfo = dynamicCallback.GetDynamicILInfo();
dynamicIlInfo.SetCode(ilBytes, 100);
dynamicCallback.Invoke(null, new object[] { "World" });
}
}
调用时dynamicCallback.Invoke(null, new object[] { "World" })
我们得到“异常抛出:mscorlib.dll 中的'System.BadImageFormatException'”。
我不知道的一件事是我应该使用什么作为第二个参数SetCode()
,应该使用什么作为'maxStackSize'?如何设置与初始操作相同的值?但我想这不是例外的原因。
如何从 IL 字节正确创建动态方法?
解决方案
这里我想总结一下 Dudi Keleti 提供的完整解决方案:
static void Main(string[] args)
{
Action<string> myAction = s =>
{
Console.WriteLine("Hello " + s);
};
MethodInfo method = myAction.GetMethodInfo();
object target = myAction.Target;
DynamicMethod dm = new DynamicMethod(
method.Name,
method.ReturnType,
new[] {method.DeclaringType}.
Concat(method.GetParameters().
Select(pi => pi.ParameterType)).ToArray(),
method.DeclaringType,
skipVisibility: true);
DynamicILInfo ilInfo = dm.GetDynamicILInfo();
var body = method.GetMethodBody();
SignatureHelper sig = SignatureHelper.GetLocalVarSigHelper();
foreach (LocalVariableInfo lvi in body.LocalVariables)
{
sig.AddArgument(lvi.LocalType, lvi.IsPinned);
}
ilInfo.SetLocalSignature(sig.GetSignature());
byte[] code = body.GetILAsByteArray();
ILReader reader = new ILReader(method);
DynamicMethodHelper.ILInfoGetTokenVisitor visitor = new DynamicMethodHelper.ILInfoGetTokenVisitor(ilInfo, code);
reader.Accept(visitor);
ilInfo.SetCode(code, body.MaxStackSize);
dm.Invoke(target, new object[] { target, "World" });
Console.ReadLine(); //Just to see the result
}