[英]Create DynamicMethod to assign value to a property?
This is a learning exercise. 这是一项学习练习。 I created a method that takes a Foo and a string and sets the A property.
我创建了一个方法,它接受一个Foo和一个字符串并设置A属性。 I used the Reflector disassembly to make the following emit code.
我使用Reflector反汇编来生成以下发射代码。 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? krunk的意思是什么,我该如何解决?
EDIT: 编辑:
I thought maybe it's because the target method is private, but I'm not so sure. 我想也许是因为目标方法是私有的,但我不太确定。 From the DynamicMethod MSDN page :
从DynamicMethod MSDN页面 :
The following code example creates a DynamicMethod that is logically associated with a type.
以下代码示例创建一个与类型逻辑关联的DynamicMethod。 This association gives it access to the private members of that type.
此关联使其可以访问该类型的私有成员。
Interesting issue. 有趣的问题。 First there are few things you can do.
首先,你可以做的事情很少。 If you only want a delegate for the setter you can use
Delegate.CreateDelegate
. 如果您只需要setter的委托,则可以使用
Delegate.CreateDelegate
。
Delegate.CreateDelegate(typeof(Action<Foo, string>),typeof(Foo).GetProperty("A").GetSetMethod()) as Action<Foo,String>;
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). 如果您使用的是.NET 3.5+,那么您可以使用表达式树,我强烈建议您通过DynamicMethod学习它们,它们在.NET 3.5中使用有限,几乎没有.NET 4.(TypeBuilder仍然非常有用)。
var targetExpression = Expression.Parameter(typeof(Foo),"target");
var valueExpression = Expression.Parameter(typeof(string),"value");
var expression = Expression.Lambda<Action<Foo,string>>(
Expression.Call(
targetExpression,
typeof(Foo).GetProperty("A").GetSetMethod(),
valueExpression
),
targetExpression,
valueExpression
);
In .NET 4 you can write it to be slightly prettier by using Expression.Assign
, but it's not much better. 在.NET 4中,您可以使用
Expression.Assign
将其编写为略微漂亮,但它并没有好多少。
Finally, if you really want to do it in IL this works. 最后,如果你真的想在IL中这样做,这是有效的。
DynamicMethod method = new DynamicMethod("Setter", typeof(void), new[] { typeof(Foo), typeof(string) }, true);
var ilgen = method.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Callvirt, typeof(Foo).GetProperty("A").GetSetMethod());
ilgen.Emit(OpCodes.Ret);
var action = method.CreateDelegate(typeof(Action<Foo,string>)) as Action<Foo,string>;
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);
我认为你的问题是你当前正在调用set方法实际上是错误在这一行的getMethod ::
MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName);
I've never assigned parameter attributes but that may also be an issue too. 我从未分配参数属性,但这也可能是一个问题。
Well I figured it out. 好吧,我明白了。 Changing
更改
IL.Emit(OpCodes.Callvirt, setMethod);
to 至
IL.Emit(OpCodes.Call, setMethod);
fixed it. 固定它。 I don't know why the disassembly showed CallVirt, but eh.
我不知道为什么反汇编会显示CallVirt,但是呃。
What version of .NET does this need to run on? 需要运行什么版本的.NET? Compiling a delegate from an expression tree would be much easier.
从表达式树编译委托会容易得多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.