创建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 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 retval = (Action)method.CreateDelegate(typeof(Action)); 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. 

krunk的意思是什么,我该如何解决?

编辑:

我想也许是因为目标方法是私有的,但我不太确定。 从DynamicMethod MSDN页面 :

以下代码示例创建一个与类型逻辑关联的DynamicMethod。 此关联使其可以访问该类型的私有成员。

有趣的问题。 首先,你可以做的事情很少。 如果您只想要setter的委托,可以使用Delegate.CreateDelegate

 Delegate.CreateDelegate(typeof(Action),typeof(Foo).GetProperty("A").GetSetMethod()) as Action; 

如果您使用的是.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>( Expression.Call( targetExpression, typeof(Foo).GetProperty("A").GetSetMethod(), valueExpression ), targetExpression, valueExpression ); 

在.NET 4中,您可以使用Expression.Assign将其写得稍微漂亮,但它并没有好多少。

最后,如果你真的想在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)) as Action; 

我认为你的问题是你当前正在调用set方法实际上是错误在这一行的getMethod :: MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName);

我从未分配参数属性,但这也可能是一个问题。

好吧我明白了。 更改

 IL.Emit(OpCodes.Callvirt, setMethod); 

 IL.Emit(OpCodes.Call, setMethod); 

固定它。 我不知道为什么反汇编会显示CallVirt,但是呃。

需要运行什么版本的.NET? 从表达式树编译委托会容易得多。