这是一个学习练习。我创建了一个接受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页面
下面的代码示例创建逻辑上与类型关联的DynamicMethod。该关联使它能够访问该类型的私有成员。
发布于 2011-01-05 04:05:34
我想出来了。改变
IL.Emit(OpCodes.Callvirt, setMethod);至
IL.Emit(OpCodes.Call, setMethod);修好了。我不知道为什么拆卸显示CallVirt,但是呃。
发布于 2011-01-11 16:55:39
有趣的问题。首先,你几乎没有什么可以做的。如果您只想要设置器的委托,则可以使用Delegate.CreateDelegate。
Delegate.CreateDelegate(typeof(Action<Foo, string>),typeof(Foo).GetProperty("A").GetSetMethod()) as Action<Foo,String>;如果您正在使用.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
);在.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<Foo,string>)) as Action<Foo,string>;我认为您的问题是,当前正在调用的set方法实际上是getMethod,错误出现在以下一行::MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName);
我从未分配过参数属性,但这也可能是一个问题。
发布于 2011-01-03 23:52:34
这需要在什么版本的.NET上运行?从表达式树编译委托要容易得多。
https://stackoverflow.com/questions/4588175
复制相似问题