C# 从操作创建DynamicMethod<;T>;说明书
我正在使用DynamicMethod,目标是执行以下操作: 我有一个操作,使用C# 从操作创建DynamicMethod<;T>;说明书,c#,reflection,dynamicmethod,C#,Reflection,Dynamicmethod,我正在使用DynamicMethod,目标是执行以下操作: 我有一个操作,使用GetILAsByteArray()从中获取IL代码作为字节。我想从这个字节创建一个动态方法并执行is。下面是我尝试做的一个例子: class Program { static void Main(string[] args) { //Create action and execute Action<string> myAction = s =>
GetILAsByteArray()
从中获取IL代码作为字节。我想从这个字节创建一个动态方法并执行is。下面是我尝试做的一个例子:
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" });
}
}
注:DynamicMethodHelper是由罗海波开发的类,在a中有描述,但也可以直接下载。您可以这样做:
byte[] code = body.GetILAsByteArray();
ILReader reader = new ILReader(method);
ILInfoGetTokenVisitor visitor = new ILInfoGetTokenVisitor(ilInfo, code);
reader.Accept(visitor);
ilInfo.SetCode(code, body.MaxStackSize);
dm.Invoke(myAction.Target, new object[] { myAction.Target, "World" });
ILReader
是一个为您完成艰苦工作的课程。你可以从中复制它
例如:
MethodInfo method = ...
DynamicMethod dm = new DynamicMethod(
method.Name,
method.ReturnType,
method.GetParameters.Select(pi => pi.ParameterType).ToArray(),
method.DeclaringType,
skipVisibility: true\fasle - depends of your need);
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);
ILInfoGetTokenVisitor visitor = new ILInfoGetTokenVisitor(ilInfo, code);
reader.Accept(visitor);
ilInfo.SetCode(code, body.MaxStackSize);
如果您的方法是一个简单的方法(不是泛型的,也没有异常句柄),那么thid应该可以工作
如果您的方法是泛型方法,则需要执行以下操作以将所有者类型传递给DynamicMethod构造函数:
var owner = method.DeclaringType.MakeGenericType(
method.DeclaringType.GetGenericArguments());
还有一件事,如果它仍然不起作用,并且您的方法是实例方法,请在DynamicMethod
构造函数的parameters数组的第一个单元格中传递该方法的instacne类型
更新
您不能在此处传递null
dm.Invoke(**null**,新对象[]{“世界”})因为myAction
不是静态方法
myAction
(Action
)实际上是一个新生成的类中的方法,该类保存该方法
但我检查了,即使我传递了myAction.Target
或该类型的新实例,也会引发异常。异常(CLR DEDEECT无效程序)告诉您IL不完全正确。我现在不能告诉你到底是什么问题,但如果这对你很重要,我可以在下周回去工作时检查一下
无论如何,如果您只想看到DynamicIlInfo.SetCode的运行,您可以按原样使用代码,但只需从以下内容更改方法信息:
class Program
{
static void Main(string[] args)
{
Action<string> myAction = s =>
{
Console.WriteLine("Hello " + s);
};
MethodInfo method = myAction.GetMethodInfo();
//Rest of your code
}
}
更新2:
显然我昨天很累,我没有意识到你的错误
正如我在最初的回答中所写
还有一件事,如果它仍然不起作用,并且您的方法是实例方法,请在DynamicMethod
构造函数的parameters数组的第一个单元格中传递该方法的instacne类型
因此,您需要这样做:
DynamicMethod dm = new DynamicMethod(
method.Name,
method.ReturnType,
new[] {method.DeclaringType}.
Concat(method.GetParameters().
Select(pi => pi.ParameterType)).ToArray(),
method.DeclaringType,
skipVisibility: true);
然后像这样调用动态方法:
byte[] code = body.GetILAsByteArray();
ILReader reader = new ILReader(method);
ILInfoGetTokenVisitor visitor = new ILInfoGetTokenVisitor(ilInfo, code);
reader.Accept(visitor);
ilInfo.SetCode(code, body.MaxStackSize);
dm.Invoke(myAction.Target, new object[] { myAction.Target, "World" });
现在,它的工作非常完美。我认为使用反射无法获得maxStackSize值。但事实上,这不是问题所在。问题是
Console.WriteLine
调用被编码为元数据标记(MethodRef可能),元数据标记仅在声明它的模块的范围内有效。查看DynamicILInfo.getToken有关
函数,这些函数将导入其他元数据项并创建对DynamicMethod
有效的令牌@thehenny我尝试过但没有成功,请参阅我的编辑。您必须用getToken
方法返回给您的新创建的标记替换IL字节数组中的旧标记。我认为我编写的代码已经没有意义,我没有立即获取它。谢谢。有没有一个通用的方法可以做到这一点,而不需要知道在行动中被称为什么?例如,是否有一种方法可以在最后动态地实现这一点?是的,您可以解析方法体字节数组,然后使用模块解析所有令牌。Resolvexxx
方法。声明的ILInfoGetTokenVisitor
在哪里?@Sjoerd222888,并且有一篇关于它的博文,我立即得到一个“System.Reflection.TargetInvocationException”,消息为:“{”错误的二进制签名。(来自HRESULT:0x80131192的异常)“}”在尝试调用动态方法时。我想我错过了一些基本信息。请查看我的更新。我仍然得到一个TargetInvocationException
。我哪里出错了?@Sjoerd222888立即检查它