创建 DynamicMethod 来为属性赋值?
这是一个学习练习。我创建了一个方法,它接受 Foo 和一个字符串并设置 A 属性。我使用 Reflector 反汇编来发出以下代码。反汇编看起来像这样:
.method private hidebysig static void Spork(class ConsoleTesting.Foo f, string 'value') cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldarg.1
L_0002: callvirt instance void ConsoleTesting.Foo::set_A(string)
L_0007: ret
}
好的,所以我在那之后建模了我的发出代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
namespace ConsoleTesting
{
class Foo
{
public string A { get; set; }
}
class Program
{
static Action<Foo, string> GenMethodAssignment(string propName)
{
MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName);
if (setMethod == null)
throw new InvalidOperationException("no property setter available");
Type[] argTypes = new Type[] { typeof(Foo), typeof(String) };
DynamicMethod method = new DynamicMethod("__dynamicMethod_Set_" + propName, null, argTypes, typeof(Program));
ILGenerator IL = method.GetILGenerator();
IL.Emit(OpCodes.Ldarg_0);
IL.Emit(OpCodes.Ldarg_1);
IL.Emit(OpCodes.Callvirt, setMethod);
IL.Emit(OpCodes.Ret);
method.DefineParameter(1, ParameterAttributes.In, "instance");
method.DefineParameter(2, ParameterAttributes.In, "value");
Action<Foo, string> retval = (Action<Foo, string>)method.CreateDelegate(typeof(Action<Foo, string>));
return retval;
}
static void Main(string[] args)
{
Foo f = new Foo();
var meth = GenMethodAssignment("A");
meth(f, "jason");
Console.ReadLine();
}
}
我得到了这个异常:
JIT Compiler encountered an internal limitation.
这是什么意思,我该如何修复它?
编辑:
我想可能是因为目标方法是私有的,但我不太确定。来自 DynamicMethod MSDN 页面< /a>:
以下代码示例创建一个与类型逻辑关联的 DynamicMethod。该关联使其能够访问该类型的私有成员。
This is a learning exercise. I created a method that takes a Foo and a string and sets the A property. I used the Reflector disassembly to make the following emit code. The disassembly looks like this:
.method private hidebysig static void Spork(class ConsoleTesting.Foo f, string 'value') cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldarg.1
L_0002: callvirt instance void ConsoleTesting.Foo::set_A(string)
L_0007: ret
}
Ok, so I modeled my emit code after that:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
namespace ConsoleTesting
{
class Foo
{
public string A { get; set; }
}
class Program
{
static Action<Foo, string> GenMethodAssignment(string propName)
{
MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName);
if (setMethod == null)
throw new InvalidOperationException("no property setter available");
Type[] argTypes = new Type[] { typeof(Foo), typeof(String) };
DynamicMethod method = new DynamicMethod("__dynamicMethod_Set_" + propName, null, argTypes, typeof(Program));
ILGenerator IL = method.GetILGenerator();
IL.Emit(OpCodes.Ldarg_0);
IL.Emit(OpCodes.Ldarg_1);
IL.Emit(OpCodes.Callvirt, setMethod);
IL.Emit(OpCodes.Ret);
method.DefineParameter(1, ParameterAttributes.In, "instance");
method.DefineParameter(2, ParameterAttributes.In, "value");
Action<Foo, string> retval = (Action<Foo, string>)method.CreateDelegate(typeof(Action<Foo, string>));
return retval;
}
static void Main(string[] args)
{
Foo f = new Foo();
var meth = GenMethodAssignment("A");
meth(f, "jason");
Console.ReadLine();
}
}
I'm getting this exception:
JIT Compiler encountered an internal limitation.
What the krunk does that mean, and how do I fix it?
EDIT:
I thought maybe it's because the target method is private, but I'm not so sure. From the DynamicMethod MSDN page:
The following code example creates a DynamicMethod that is logically associated with a type. This association gives it access to the private members of that type.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
有趣的问题。首先,您可以做几件事。如果您只需要 setter 的委托,则可以使用
Delegate.CreateDelegate
。如果您使用 .NET 3.5+,则可以使用表达式树,我强烈建议通过 DynamicMethod 学习它们,它们在 .NET 3.5 中的使用有限,在 .NET 4 中几乎没有。(尽管 TypeBuilder 仍然非常有用)。
在 .NET 4 中,您可以使用
Expression.Assign
将其编写得稍微漂亮一些,但也好不了多少。最后,如果你真的想在 IL 中做到这一点,这是可行的。
我认为你的问题是你当前调用的 set 方法实际上是 getMethod 错误就在这一行::
MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName);
我从未分配过参数属性,但这也可能是一个问题。
Interesting issue. First there are few things you can do. If you only want a delegate for the setter you can use
Delegate.CreateDelegate
.If you are using .NET 3.5+ you can use expression trees and I strongly recommend learning them over DynamicMethod, they have limited use in .NET 3.5 and almost none .NET 4. (TypeBuilder is still very useful though).
In .NET 4 you can write it to be slightly prettier by using
Expression.Assign
, but it's not much better.Finally, if you really want to do it in IL this works.
I think your issue is that you are currently calling the set method is actually the getMethod the error is on this line::
MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName);
I've never assigned parameter attributes but that may also be an issue too.
好吧,我想通了。更改
以
修复它。我不知道为什么反汇编显示 CallVirt,但是呃。
Well I figured it out. Changing
to
fixed it. I don't know why the disassembly showed CallVirt, but eh.
这需要在什么版本的 .NET 上运行?从表达式树编译委托会容易得多。
What version of .NET does this need to run on? Compiling a delegate from an expression tree would be much easier.